home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 21
/
Aminet 21 (1997)(GTI - Schatztruhe)[!][Oct 1997].iso
/
Aminet
/
dev
/
c
/
FW_ACMint.lha
/
ACE-Intuition
(
.txt
)
< prev
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS
UTF-8
Wrap
Final Write Document
|
1997-07-18
|
635.7 KB
|
7,441 lines
Chapter 1 "SCREENS"
1.1 Introduction
1.2 Different Types of Screens
1.3 Workbench Screen
1.4 Custom Screens
1.4.1 Resolution
1.4.2 Depth
1.4.3 Interlace
1.4.4 HAM and Extra HalfBrite
1.4.5 Dual Playfields
1.4.6 Fonts
1.4.7 Size and Position
1.4.8 Title
1.4.9 Gadgets
1.5 Iinitialize a Cuztom Screen
1.6 Open a Custom Screen
1.7 Screen Structure
1.8 Functions
1.9 Examples
Chapter 2 "WINDOWS"
2.1 Introduction
2.2 Special Windows
2.2.1 Backdrop Windows
2.2.2 Borderless Windows
2.2.3 GimmeZeroZero Windows
2.2.4 Superbitmap Windows
2.3 System Gadgets
2.4 Redrawing the Window Display
2.5 Initialize a Window
2.6 Open a Window
2.7 Window Structure
2.8 Open a Superbitmap Window
2.9 Make Your Own custom Pointer
2.10 Functions
2.11 Examples
Chapter 3 "GRAPHICS"
3.1 Introduction
3.2 Lines Text Pictures
3.3 Borders
3.3.1 The Border Structure
3.3.2 Coordinates
3.4 How to Use the Border Structure
3.4 Text
3.4.1 The Intuitext Structure
3.4.2 Fonts
3.4.3 How to Use the Intuitext Structure
3.5 Images
3.5.1 Image Data
3.5.2 The Image Structure
3.5.3 PlanePick
3.5.4 PlaneOnOff
3.5.5 How to Use the Image Structure
3.6 Functions
3.7 Examples
Chapter 4 "GADGETS"
4.1 Introduction
4.2 Different Types of Gadgets
4.3 Custom Gadgets
4.3.1 Graphics for Custom Gadgets
4.3.2 Position
4.3.3 Size
4.4 Initialize a Custom Gadget
4.5 Boolean Gadget
4.6 String/Integer Gadget
4.6.1 StringInfo Structure
4.6.2 Initialize a String/Integer Gadget
4.6.3 Usign a String/Integer Gadget
4.7 Proportional Gadget
4.7.1 PropInfo Structure
4.7.2 Initialize a Proportional Gadget
4.8 Monitoring the Gadgets
4.9 Functions
4.10 Examples
Chapter 5 "REQUESTERS"
5.1 Introduction
5.2 Different Types of Requesters
5.2.1 System Requesters
5.2.2 Application Requesters
5.2.3 Double-Menu Requesters
5.3 Graphics for Requesters
5.4 Position
5.5 Requesters andGadgets
5.6 Simple Requesters
5.7 Open a Requester
5.7.1 Initialize a Requester
5.7.2 How to Activate an Application Requester
5.8 IDCMP Flags
5.9 Functions
5.10 Examples
Chapter 6 "ALERTS"
6.1 Introduction
6.2 Different Levels of Warnings
6.3 How to Use the DisplayAlert() Function
6.4 Examples of Strings and Substrings
6.5 Functions
6.6 Examples
Chapter 7 "MENUS"
7.1 Introduction
7.2 Menu Design
7.3 How to Access Menus From the Keyboard
7.4 Menu Items
7.5 Mutual Exclude
7.6 Open a Menu
7.6.1 Initialize a Menu Structure
7.6.2 Initialize a MenuItem Structure
7.6.3 How to Submit and Remove a Menu Strip To/From a Window
7.7 Special IDCMP Flags
7.7.1 MenuPick
7.7.2 MenuVerify
7.8 Menu Nubers
7.9 Functions
7.10 Macros
7.11 Examples
Chapter 8 "IDCMP"
8.1 Introduction
8.2 IDCMP Ports
8.3 How to Recieve IDCMP Messages
8.3.1 Open IDCMP Ports
8.3.2 Wait for Messages
8.3.3 Collect Messages
8.3.4 Examine the Message
8.3.5 Reply
8.3.6 Example
8.4 IDCMP Flags
8.5 Functions
8.6 Examples
Chapter 9 "MISCELLANEOUS"
9.1 Introduction
9.2 Memory
9.2.1 Allocate Memory
9.2.2 Deallocate Memory
9.2.3 Remember Memory
9.3 Preferences
9.4 Warnings
9.5 Double Click
9.6 Time
9.7 Style
9.7.1 Gadgets
9.7.2 Requesters
9.7.3 Menus
9.7.4 Mouse
9.8 Functions
9.9 Examples
Chapter 10 "File Window"
Chapter 11 "Colour Window"
TABLE OF CONTENTS
SCREENS
1.1 INTRODUCTION
The screen is the foundation of Intuition's display. It determines how many
colours you can use, what kind of colours, what resolution etc. Every window,
gadget, icon, drawing is connected to a screen. Moving that screen, and you are
also moving the objects on it. You may have several screens running at the same
time, and you may combine different screens (with their own individual
resolutions, colours, etc) on the same display.
In this chapter we will only look at the "standard screens" which all Amiga
models support. There exist new models like the Amiga 3000 which can use new
types screens with different sizes and limitations. Since only some models
support these new modes there will be a special chapter about this.
What is described in the following chapters will work on all Amiga models.
1.2 DIFFERENT TYPES OF SCREENS
When you are going to use a screen you first need to decide if you want to use
a Standard (Workbench) Screen or if you want to use a Screen which you yourself
have customized (Custom Screens).
Workbench Screen:
This is Intuition's standard screen. It is a four-colour, high-resolution
screen.
Custom Screens:
When you want a screen with your own display mode you should use a Custom
Screen. You can then decide yourself how many colours you want, what colours,
resolution, size etc.
If your program should use a high-resolution screen, and four colours is
enough, you are advised to use the Workbench Screen. This will save a lot of
memory (no memory allocated for a Custom Screen), and allows the user to have
several programs running on the same display. On the other hand, if you want
more colours or want to use a different resolution/display-mode you should use
a Custom Screen.
1.3 WORKBENCH SCREEN
Workbench Screen is a high-resolution (640 pixels wide), four colour screen. It
is either 200 or 256 lines high depending on if you have a NTSC (American) or a
PAL (European) computer. (400/512 lines if you have an Interlaced display.)
The Workbench Screen will automatically open if there does not exist any other
screens. If you do not want the Workbench Screen, and need a lot of memory, you
can try to close it, CloseWorkBench(). Remember to reopen it when your program
has finished, OpenWorkBench().
You are advised to always call the function OpenWorkBench() when your program
exits, even if you have not closed it yourself. Another program may have closed
it because of shortage of memory, and when your program is finished there may
exist enough memory. This will make the Workbench Screen
available as much as possible.
1.4 CUSTOM SCREENS
If you are going to use a Custom Screen you need to initialize a structure
(NewScreen) with your requirements. You also need to open the screen yourself
by calling the function OpenScreen().
Here is a list of some important decisions you need to make before you can open
the screen:
1.4.1 RESOLUTION
You can either have a high-resolution or a low-resolution screen. A high
resolution screen is 640 pixels wide, while a low-resolution screen is only 320
pixels wide. However, a high- resolution screen may only have a depth of up to
4 (maximum 16 colours), while a low-resolution screen may have a depth of up
to 5 (32 colours), or even 6 if using some special display modes.
1.4.2 DEPTH
A screen's depth means how many bits are used for every pixel. The more bits
the more combinations/colours:
Depth
Number of
Colour register
colours
number
--------------------------------------------------
1 2
0 - 1
2 4
0 - 3
3 8
0 - 7
4 16
0 - 15
5 32
0 - 31 (Only low-res)
A low resolution screen may even have a depth of 6 if using some special
display modes (HAM / EXTRA HALFBRIGHTE ).
Each colour may be picked out of a 4096 colour palette. Once you have opened
your Custom Screen you may change the colours by calling the graphics function
SetRGB4().
1.4.3 INTERLACED
An Interlaced screen can be 400/512 lines while a Non-Interlaced screen can
only be 200/256 lines. You are recommended to use a Non-Interlaced screen if
possible, since an Interlaced display appear to "flicker" if the user does not
have a special high-phosphor-persistence monitor. (99% of the users do not
have it.)
The monitor normally draws the display 50 times per second. If you are using an
Interlaced screen the Amiga will only draw every second line first, and will
the next time draw the remaining lines. This is why an Interlaced display
appear to "flicker". You can eliminate much of the disturbing effects if you
are using colours with low contrasts, black and grey instead of black and white
for example.
1.4.4 HAM AND EXTRA HALFBRIGHTE
If you have a low-resolution, six bitplanes (Depth 6) screen you can either use
the special HAM mode, or the Extra Halfbrighte mode. HAM allows you to display
all 4096 colours at the same time, but has some restrictions, and is
complicated to use. Extra Halfbrighte gives you 32 extra colours, which are the
same as the first 32 colours, but are a bit brighter.
Both HAM and Extra Halfbrighte is using a lot of memory/processing time, and is
therefore not commonly used.
1.4.5 DUAL PLAYFIELDS
Dual Playfields allows you to have two screens on top of each other. The top
screen can then be transparent in some places (colour register 0) to show the
bottom screen.
1.4.6 FONTS
You can specify a default font which will be used, if nothing else is
specified, to draw the text on the screen. The system's default font is called
Topaz and exist in two sizes:
TOPAZ_SIXTY : 9 lines tall, 64/32 characters per line.
TOPAZ_EIGHTY : 8 lines tall, 80/40 characters per line.
This font is built in the Amiga, and is therefore always available. (See
chapter 3 GRAPHICS for more information.)
1.4.7 SIZE AND POSITION
The top of your screen does not need to be at the top of the display. You may
open several screens and position them under each other. If you are, for
example, designing an adventure game, you can have a low-resolution 32 colour
screen at the top of the display (showing some nice pictures), and have a high-
resolution 2 colour screen at the bottom of the display (showing the text).
(Remember that the user later can drag the screens up or down himself.)
The width of the screen should be either 320 (low-resolution) or 640 pixels
(high-resolution).
The height may be anything between 1 - 200/256 lines on an Non- Interlaced
screen, and between 1 - 400/512 lines on an Interlaced display.
1.4.8 TITLE
On top of each screen (on the "drag bar") there exist a screentitle. There
exist two kinds of titles:
- The default title, which is specified in the NewScreen structure.
- A "current" title which is the same as the title of the current active
window. (See chapter 2 WINDOWS for more information.)
1.4.9 GADGETS
For the moment you are not allowed to attach any custom gadgets to a screen.
(See chapter 4 GADGETS for more information about gadgets.)
1.5 INITIALIZE A CUSTOM SCREEN
Before you can open a custom screen you need to initialize a NewScreen
structure which look like this:
struct NewScreen
{
SHORT LeftEdge, TopEdge, Width, Height, Depth;
UBYTE DetailPen, BlockPen;
USHORT ViewModes;
USHORT Type;
struct TextAttr *Font;
UBYTE *DefaultTitle;
struct Gadget *Gadgets;
struct BitMap *CustomBitMap;
};
LeftEdge:
Initial x position of the screen. Should always be 0.
TopEdge:
Initial y position of the screen.
Width:
If it is a low-resolution screen it should be 320, otherwise 640.
Height:
If it is a Non-Interlaced screen it can be anything between 1 - 200/256,
otherwise 1 - 400/512.
Depth:
1-4 if high-resolution, otherwise 1-6.
DetailPen:
The colour register used to draw the text with.
BlockPen:
The colour register used for block fills etc.
ViewModes:
You can use none or some of the flags. If you set more than one flag you put a
"|" between them. (You are not allowed to set the HIRES flag together with the
DUALPF or HAM flag, and you can not have DUALPF at the same time as HAM.)
HIRES
Set this flag if you want a high- resolution screen. (The default is
low-resolution.)
INTERLACE
Set this flag if you want an Interlaced screen. (The default is
Non-Interlaced)
SPRITES
Set this flag if you are going to use sprites in your display.
DUALPF
Set this flag if you want to use the Dual Playfields Mode.
HAM
Set this flag if you want to use the Hold And Modify Mode.
Type:
Should be CUSTOMSCREEN. You can also set the CUSTOMBITMAP flag if you want the
screen to use your own declared and initialized BitMap. (See chapter 2 WINDOWS
for more information about Custom BitMaps.)
Font:
A pointer to an already initialized TextAttr structure. The screen will use it
as the default font. (See chapter 3 GRAPHICS for more information about fonts.)
Set to NULL if you want to use the current default font.
DefaultTitle:
A pointer to a text string which will be used as "default" title.
Gadgets:
Not used for the moment. Set to NULL.
CustomBitMap:
If you want to use your own BitMap you should give this field a pointer to the
BitMap structure which you have declared, and initialized yourself. Remember to
set the CUSTOMBITMAP flag in the Type variable. However, if you want Intuition
to take care of the BitMap, set this field to NULL. (See chapter 2 WINDOWS for
more information about Custom BitMaps.)
1.6 OPEN A CUSTOM SCREEN
Once you have declared and initialized the NewScreen structure, you can call
the function OpenScreen() which will open your Custom Screen. When your screen
has been opened you can, if you have allocated memory for the NewScreen
structure, deallocate it since you do not need the structure any more.
This is how you call the OpenScreen() function:
my_screen = OpenScreen( &my_new_screen );
my_screen has been declared as:
struct Screen *my_screen;
my_new_screen has been declared as:
struct NewScreen my_new_screen;
and has been initialized with your requirements.
OpenScreen() will return a pointer to a Screen structure, else
NULL if it could not open the screen (for example, not enough
memory). Remember to check what OpenScreen() returned!
if( my_screen==NULL )
{
/* PANIC! Could not open the screen */
}
1.7 SCREEN STRUCTURE
Once you have opened the screen you will receive a pointer to a Screen
structure which look like this:
struct Screen
{
struct Screen *NextScreen; /* Pointer to the next */
/* screen, or NULL. */
struct Window *FirstWindow; /* Pointer to the first */
/* Window on this screen. */
SHORT LeftEdge, TopEdge; /* Position of the screen. */
SHORT Width, Height; /* Size of the screen. */
SHORT MouseY, MouseX; /* Mouse position relative */
/* to the top left corner */
/* of the screen. */
USHORT Flags; /* The selected flags. */
UBYTE *Title; /* The screen's Current title. */
UBYTE *DefaultTitle; /* The screen's Default title. */
BYTE BarHeight, BarVBorder,
BarHBorder, MenuVBorder,
MenuHBorder;
BYTE WBorTop, WBorLeft,
WBorRight, WBorBottom;
struct TextAttr *Font; /* The screens default font. */
struct ViewPort ViewPort; /* The screen's ViewPort etc: */
struct RastPort RastPort;
struct BitMap BitMap;
struct Layer_Info LayerInfo;
struct Gadget *FirstGadget;
UBYTE DetailPen, BlockPen;
USHORT SaveColor0;
struct Layer *BarLayer;
UBYTE *ExtData;
UBYTE *UserData;
};
You will probably not use this structure a lot, but some variables/structures
can be useful later on. When you are, for example, using the function
SetRGB4(). More about this later.
1.8 FUNCTIONS
Here are some common functions which will affect screens:
OpenScreen()
This function will open a Custom Screen with your requirements.
Synopsis
:
my_screen = OpenScreen( my_new_screen );
my_screen:
(struct Screen *) Pointer to a Screen structure. It will point to your newly
opened screen or be equal to NULL if the screen could not be opened.
my_new_screen:
(struct NewScreen *) Pointer to a NewScreen structure which contains your
preferences.
CloseScreen()
This function will close a Custom Screen which you have previously opened.
Synopsis:
CloseScreen( my_screen );
my_screen:
(struct Screen *) Pointer to an already opened screen.
All windows (See chapter 2 WINDOWS for more information) on your Screen MUST
have been closed before you may close the screen. If you close a window after
the screen has been
closed, the system will crash. (Not recommended.)
If there does not exist any more screens when you close yours, Intuition will
automatically reopen the Workbench Screen.
MoveScreen()
This function will move the screen. For the moment you may
only move it vertically.
Synopsis:
MoveScreen( my_screen, delta_x, delta_y );
my_screen:
(struct Screen *) Pointer to the screen which you want to move.
delta_x:
(long) Number of pixels which the screen should move horizontally. For the
moment you may not move a screen horizontally, set it therefore to 0.
delta_y:
(long) Number of lines which the screen should move vertically.
ScreenToBack()
This will move the screen behind all other screens.
Synopsis:
ScreenToBack( my_screen );
my_screen:
(struct Screen *) Pointer to the screen which you want to move.
ScreenToFront()
This will move the screen in front of all other screens.
Synopsis:
ScreenToFront( my_screen );
my_screen:
(struct Screen *) Pointer to the screen which you want to move.
ShowTitle()
This function will make the screen's Title appear above or behind any Backdrop
Windows (See chapter 2 WINDOWS for more information about Backdrop Windows).
(The screen's title appear always behind normal windows.)
Synopsis: ShowTitle( my_screen, show_it );
my_screen:
(struct Screen *) Pointer to the screen.
show_it:
(long) A boolean value which can be:
TRUE: The title will be in front of any Backdrop Windows, but behind any other
windows.
FALSE: The Title will be behind any windows.
OpenWorkBench()
This function will try to open the Workbench Screen if there exist enough
memory.
Synopsis:
result = OpenWorkBench();
result:
(long) A boolean value which tell us if the Workbench Screen has been (or
already was) opened (TRUE), or not (FALSE).
CloseWorkBench()
This function will try to close the Workbench Screen if possible. If any other
programs is using the Workbench Screen, the function can not close it. Closing
the Workbench will free some memory, and can therefore be used if your program
needs more memory.
(Remember to reopen the Workbench Screen when your program terminates.)
Synopsis:
result = CloseWorkBench();
result:
(long) A boolean value which tell us if the Workbench screen has been (or
already was) closed (TRUE), or not (FALSE).
WBenchToBack()
This will move the Workbench Screen behind all other screens.
Synopsis:
result = WBenchToBack();
result:
(long) A boolean value which is TRUE if the Workbench screen was open, or FALSE
it it was not.
WBenchToFront()
This will move the Workbench Screen in front of all other screens.
Synopsis:
result = WBenchToFront();
result:
(long) A boolean value which is TRUE if the Workbench screen was open, or FALSE
it it was not.
SetRGB4()
This function allows you to change your screen's colours. Each colour may be
picked out of a 4096 colour palette. (16 levels of red, 16 levels of green and
16 levels of blue; 16*16*16 = 4096.)
IMPORTANT! Before you may use this function you must have opened the Graphics
Library. (All other functions are in the Intuition Library.) (See chapter 0
INTRODUCTION for more information.)
Synopsis:
SetRGB4( viewport, register, red, green, blue );
viewport:
(struct ViewPort *) Pointer to a ViewPort which colour registers we are going
to change. We can find the screen's ViewPort in the Screen structure. (If
my_screen is a pointer to a Screen structure, this will get us a pointer to
that screen's ViewPort: &my_screen->ViewPort)
register:
(long) The colour register you want to change. The screen's Depth decides how
many colour registers the screen have:
Colour
Depth
Registers
1
0 - 1
2
0 - 3
3
0 - 7
4
0 - 15
5
0 - 31
6
0 - 63
red: Amount of red. (0 - 15)
green: Amount of green. (0 - 15 )
blue: Amount of blue. (0 - 15 )
Eg: SetRGB4( &my_screen->ViewPort, 2, 15, 15, 0 ); will change colour register
2 to be light yellow. (Red and green together will be yellow.)
1.9 EXAMPLES
We have now talked about different screens, Workbench Screen and your own
Custom Screens. We have looked at how you can change the Custom Screen's
display mode, resolution, depth etc, and we have described some important
functions. It is now time for us to have some examples to clear up any
confusions.
Example 1
This program will open a low-resolution, non-Interlaced, eight colour Custom
Screen. It will display it for 30 seconds, and then close it.
Example 2
Same as Example 1 except that the screen will be a high-resolution, Interlaced,
4 colour Custom Screen.
Example 3
Same as Example 1 except that we will use the TOPAZ_SIXTY Italic style as
default font. (See chapter 3 GRAPHICS for more information about text styles.)
Example 4
This program will open two screens, one (low-resolution 32 colours) at the top
of the display, and one (high-resolution 16 colours) a bit down.
Example 5
Same as Example 4 except that after 10 seconds the low- resolution screen will
move down 75 lines. After another 10 seconds it will be put in front of all
other screens. 10 seconds later it will move down another 75 lines. The program
will wait 10 seconds before the screens are closed and the program exits.
Example 6
This program will open a low-resolution, non-Interlaced, 4 colour Custom
Screen. It will after 5 seconds start to change the screens colours, and will
after a while close the screen and exit.
WINDOWS
2.1 INTRODUCTION
Windows are rectangular boxes which can be as big as the screen or only 1 pixel
wide. They can be resized, moved around on the screen, put in front or behind
other windows and so on. All this is taken care of by Intuition, and your
program does not even need to know about it if you do not want.
The aim with Windows is to make the communication between the user and the
computer as easy as possible. Windows gives the user a structured display which
is easy to understand. It also allows the user to interact with the programs
through graphics symbols (gadgets) which can be connected to the windows. (See
chapter 4 GADGETS for more information about gadgets.)
Windows are working close together with screens, since the screen's resolution
etc affects the way the windows are drawn. Moving a screen will also result in
moving all the windows connected to that screen.
2.2 SPECIAL WINDOWS
The normal windows are rectangular boxes with a border around. However, there
exist some special types of windows:
2.2.1 BACKDROP WINDOWS
Backdrop Windows will always be behind any other windows. This allows you to
have a window in the bottom of the display, and it will stay there, even if the
user is using the "depth-arrange gadgets".
Backdrop Windows differ from other windows since:
- It will always open behind all other windows, including other already opened
Backdrop Windows.
- The "close-window gadget" is the only System Gadget you can attach to a
Backdrop Window. (You can of course attach your own gadgets as usual.)
- It will always be behind any other windows.
The Backdrop Window is very handy when you want to have a bottom drawing (for
example your main display), with some tools etc on top of the bottom window.
This allows the user to move around your tools as he/she wants without needing
to worry about hiding the windows behind the main display.
Drawing into a Backdrop Window instead of the screen itself is very common
since you can then not draw anything at the wrong moment. If a menu (See
chapter 5 MENUS for more information) is displayed, the drawing routines will
wait automatically, and will therefore not destroy the menu, as it would have
happened if you were drawing directly into the screen.
2.2.2 BORDERLESS WINDOWS
Borderless windows are as normal windows except that they (surprise, surprise)
do not have any borders. It is very common to combine a Borderless window with
a Backdrop window, to cover a screen.
It can be confusing for the user if a Borderless window does not cover the
entire display, since he/she will not be able to see where the window's edges
are. It is therefore normally best to make a Borderless window as big as the
screen.
2.2.3 GIMMEZEROZERO WINDOWS
A Gimmezerozero Window is as a normal window, except that it consist of two
drawing areas: one Outer and one Inner window. The Outer window is used for
displaying the borders, system gadgets etc, while the Inner window is only used
by yourself.
If you are drawing into a normal window you need to start some pixels down/out
(11, 1), so you do not draw into the borders etc. However, if you are drawing
into a Gimmezerozero Window you do not need to make any adjustments. The top
left corner of your inner window is always at the position (0,0).
Gimmezerozero Windows are therefore very handy if you want to make a lot of
drawings, without wanting to worry about the borders. The disadvantages is that
it takes more memory and processing time than a normal window.
2.2.4 SUPERBITMAP WINDOWS
If you are using a SuperBitMap Window you allocate display memory yourself for
the window instead of letting Intuition take care of it. The advantage is that
you can define a larger drawing area than the size of the window. You can then
scroll the drawing area inside the window. A good example of this are the demo
programs that followed with you Workbench disk when you bought your computer.
It normally best to combine a SuperBitMap Window together with a Gimmezerozero
Window. The borders etc will then NOT be drawn into your SuperBitMap, and will
instead be drawn in the Outer window. This allows you to make whatever you want
with the inner window without destroying any borders etc.
2.3 SYSTEM GADGETS
The System Gadgets enables the user to move the window, resize it, push it
behind other windows etc, without your program even knowing about it. The
System Gadgets are controlled by Intuition, and are always looking the same.
The only thing you need to do is to tell Intuition which gadgets you want, and
the rest is done for you.
The five System Gadgets are placed like this:
1 2 3 4
[*][***********][*][*]
| |
| WINDOW |
| |
| |
|__________________[*]
5
1 Close Gadget. Press this to close the window. (This is the only System
Gadget which your program have to respond to. Your program will be told that
the user has clicked on the Close Gadget, but you need to close the window
yourself by calling the function CloseWindow().)
2 Drag Gadget. Pressing the left mouse button somewhere on it and move the
mouse while the button is still pressed, will move the window. If your window
has a title it will be displayed over the Drag Gadget, but will not interfere
with it.
3 Depth-Arrangement Gadget BACK. Clicking on this gadget will push the window
behind all other windows.
4 Depth-Arrangement Gadget UP. Clicking on this gadget will put the window in
front of all other windows.
5 Sizing Gadget. Pressing the left mouse button somewhere on it and move the
mouse while the button is still pressed, will change the size of the window.
2.4 REDRAWING THE WINDOW DISPLAY
Since windows can be dragged around the screen it is very common that they
sometimes overlap each other. If the user is then moving away the top window,
the bottom window has to be refreshed.
There exist two methods of redrawing the window:
- Simple Refresh. Intuition will only tell you that you need to refresh it, and
your program has to redraw everything itself.
- Smart Refresh. Intuition saves the obscured pieces, and replaces them
automatically. Needs more memory than Simple Refresh, but redraws the display
much faster.
If you have a SuperBitMap Window, you have allocated the display memory
yourself, and your window will therefore not be destroyed by other windows.
If you change the size of a Simple Refresh Window, or it is revealed after
having been overlapped, Intuition will tell you that you need to refresh the
window. A Smart Refresh Window will only ask you to redraw its display if you
enlarged it.
The IDCMP message "REFRESHWINDOW" tells you that the window needs to be
refreshed. (See chapter 8 IDCMP for more about IDCMP flags.)
IMPORTANT! If your program receive a REFRESHWINDOW message you must call the
functions BeginRefresh() - EndRefresh():
- BeginRefresh() will make the redrawing as fast as possible. Only the
destroyed pieces of the window will be refreshed.
- EndRefresh() tells Intuition that you are finished with the redrawing.
If you receive a REFRESHWINDOW message and you do not want to redraw the
display, you should still call the two functions. This will clear up the system
and reorganize the Layer Library.
2.5 INITIALIZE A WINDOW
Before you can open a window you need to initialize a NewWindow structure which
looks like this:
struct NewWindow
{
SHORT LeftEdge, TopEdge;
SHORT Width, Height;
UBYTE DetailPen, BlockPen;
ULONG IDCMPFlags;
ULONG Flags;
struct Gadget *FirstGadget;
struct Image *CheckMark;
UBYTE *Title;
struct Screen *Screen;
struct BitMap *BitMap;
SHORT MinWidth, MinHeight;
SHORT MaxWidth, MaxHeight;
USHORT Type;
};
LeftEdge:
Initial x position of the window.
TopEdge:
Initial y position of the window.
Width:
Initial width of the window. If the window is connected to a high-resolution
screen, it can be anything between 1 and 640. Otherwise (low-resolution screen)
it can be between 1 and 320.
Height:
Initial height of the window. Can be anything between 1 and the height of the
screen.
DetailPen:
The colour register used to draw the text with.
BlockPen:
The colour register used for block fills etc.
IDCMPFlags:
See chapter 8 IDCMP for a list and explanations of the flags.
Flags:
If you want any System Gadgets, a special window (Borderless, Backdrop etc),
you set the desired flags:
System Gadgets:
WINDOWCLOSE This will put the Close Gadget into the top left corner of your
window. (Remember that this is the only System Gadget your program need to
response to. Intuition will simply inform you that the user wants to close the
window, but you need to close the window yourself by calling the CloseWindow()
function.
WINDOWDRAG This makes the whole title bar into a gadget, which allows the user
to move around the Window.
WINDOWDEPTH If you want that the user should be able to push the window in
front, or behind all other windows you set this flag. The gadgets (to the back
and to the front) will be placed in the top right corner of the window.
WINDOWSIZING This enables the user to resize the window as desired. (You can
specify the maximum and minimum size of the window by setting the
MinWidth/MinHeight/MaxWidth/MaxHeight variables)
The Size Gadget will be placed in the right border as default (SIZEBRIGHT), but
can also be put in the bottom border (set the flag SIZEBOTTOM) if you want the
window display to be as wide as possible.
Special Windows:
BACKDROP Set this flag if you want a Backdrop Window.
BORDERLESS Set this flag if you want a Borderless Window.
GIMMEZEROZERO Set this flag if you want a Gimmezerozero Window.
SUPER_BITMAP Set this flag if you want a SuperBitMap Window. (If you are going
to use your own allocated BitMap you also need to set the BitMap variable to
point to your BitMap structure. Explained later in this chapter.)
Refreshing Flags. If you do not use a SuperBitMap Window you need to set one of
these two flags:
SIMPLE_REFRESH Your program must redraw the display itself.
SMART_REFRESH Intuition will automatically redraw the display if necessary. It
is only when the user make the window bigger you need to redraw the display
yourself.
Other flags:
REPORTMOUSE Set this flag if you want to receive the pointer movements as x,y
coordinates. (See chapter 8 IDCMP for more information.)
NOCAREREFRESH Set this flag if you do not want to receive any messages telling
you to redraw your window.
RMBTRAP Set this flag if you do not want that the user to be able to access any
menus while this window is active. (If you want that the right mouse button on
the mouse should be used for something else than menu operations, you should
set this flag. See chapter 8 IDCMP for more information.)
ACTIVATE Set this flag if you want the window to become active when it is
opened. The user can of course activate some other window later if he/she
wants. (Clicking inside a window will activate it, and all input will go to the
new active window. All other windows will become inactive, and their title bars
will become "ghosted".)
FirstGadget:
A pointer to the first Gadget in your list, or NULL if you do not have any own
gadgets connected to the window. (See chapter 4 GADGETS for more information
about gadgets.)
CheckMark:
A pointer to an Image structure (See chapter 3 GRAPHICS for more information
about Image structures) which will be used for selected menus items. (See
chapter 7 MENUS for more information about menus.) If no pointer is given
(NULL) Intuition will use the default checkmark.
Title:
A pointer to a NULL-terminated string that will be used as window's title. The
string will appear on the title bar, at the top of the window.
Screen:
A pointer to your Custom Screen, or NULL if the window should be connected to
the Workbench Screen. (If the window is connected to the Workbench Screen set
the Type variable to WBENCHSCREEN, otherwise set it to CUSTOMSCREEN.)
BitMap:
If you are going to use a SuperBitMap Window, then you need to give Intuition a
pointer to your own initialized BitMap structure, otherwise write NULL.
(Remember to set the Flag SUPER_BITMAP, and you should probably also make the
window into a Gimmezerozero Window.)
If you have asked for the System Gadget WINDOWSIZING you need to decide the
minimum/maximum size of your window, otherwise you can ignore these variables.
If any variable is set to zero the initial size (Width/Height) will be used as
max/min size:
MinWidth:
Minimum width of the window.
MinHeight:
Minimum height of the window.
MaxWidth:
Maximum width of the window.
MaxHeight:
Maximum height of the window.
Type:
If your window should be connected to the Workbench Screen you write
WBENCHSCREEN, otherwise you write CUSTOMSCREEN. (If you set the CUSTOMSCREEN
flag you need to give the Screen variable a pointer to your already opened
Custom Screen.
It is common that you declare and initialize the NewWindow structure with your
requirements, except that you ignore (NULL) the Screen pointer. You then open
your Custom Screen, and first now initialize the Screen pointer with the
pointer returned from the OpenScreen() function. (See Example 2 for more
information.)
2.6 OPEN A WINDOW
The procedure to open windows is very similar to open Custom Screens. The idea
is that you declare a NewWindow structure (similar to NewScreen) and initialize
it with the requirements You then simply call the function OpenWindow()
(similar to OpenScreen()) with your NewWindow structure, and the function
returns a pointer to your Window structure. You will now not need the NewWindow
structure any more (if you do not want to open more windows using the same
structure of course).
This is how you call the OpenWindow() function:
my_window = OpenWindow( &my_new_window );
my_window has been declared as:
struct Window *my_window;
my_new_window has been declared as:
struct NewWindow my_new_window;
and has been initialized with your requirements.
OpenWindow() will return a pointer to your Window structure. If it could not
open the Window (for example, not enough memory) it will return NULL. Remember
therefore to check what OpenWindow() returned:
if( my_window == NULL )
{
/* PANIC! Could not open the window */
}
2.7 WINDOW STRUCTURE
Once you have opened the window you will receive a pointer (my_window) to a
Window structure:
struct Window
{
struct Window *NextWindow; /* Pointer to next window. */
SHORT LeftEdge, TopEdge; /* Position of the window. */
SHORT Width, Height; /* Size of the window. */
SHORT MouseY, MouseX; /* Position of the pointer */
/* relative to the top left */
/* corner of the window. */
SHORT MinWidth, MinHeight; /* Minimum/Maximum size of */
USHORT MaxWidth, MaxHeight; /* the window. */
ULONG Flags; /* The window's flags. */
struct Menu *MenuStrip; /* Pointer to the window's */
/* first menu. */
UBYTE *Title; /* The window's title. */
struct Requester *FirstRequest;
struct Requester *DMRequest;
SHORT ReqCount;
struct Screen *WScreen; /* A pointer to the Screen */
/* which the window is */
/* connected to. */
struct RastPort *RPort; /* The window's RastPort. */
BYTE BorderLeft, BorderTop, BorderRight, BorderBottom;
struct RastPort *BorderRPort; /* If your window is a */
/* Gimmezerozero this a */
/* pointer the the Outer */
/* window's RastPort. */
struct Gadget *FirstGadget;
struct Window *Parent, *Descendant;
USHORT *Pointer; /* Data for the Pointer. */
BYTE PtrHeight; /* Height of the pointer. */
BYTE PtrWidth; /* Width of the pointer. */
BYTE XOffset, YOffset; /* "Hot Spot" of the pointer. */
ULONG IDCMPFlags; /* The IDCMP flags. */
struct MsgPort *UserPort, *WindowPort;
struct IntuiMessage *MessageKey;
UBYTE DetailPen, BlockPen;
struct Image *CheckMark;
UBYTE *ScreenTitle; /* The title of the screen */
/* which the window is */
/* connected to. */
/* These are only used if you have opened a */
/* Gimmezerozero window: */
SHORT GZZMouseX; /* Position of the mouse relative to */
SHORT GZZMouseY; /* the inner window. */
SHORT GZZWidth; /* Size of the inner window. */
SHORT GZZHeight;
UBYTE *ExtData;
BYTE *UserData;
struct Layer *WLayer;
struct TextFont *IFont;
};
2.8 OPEN A SUPERBITMAP WINDOW
The difference in opening a normal window and a SuperBitMap window is that
Intuition will allocate display memory for the normal window automatically,
while a SuperBitMap window has to allocate the memory itself. However, it is
actually not so hard as it may seem. You just need to follow these steps:
1. Declare and initialize a NewWindow structure with your requirements.
(Set the Flags = SUPER_BITMAP, and BitMap=NULL)
struct NewWindow my_new_window={ .... };
2. Declare a BitMap structure:
struct BitMap my_bitmap;
3. Initialize your own BitMap by calling the function:
InitBitMap( &my_bitmap, Depth, Width, Height );
&my_bitmap:
A pointer to the my_bitmap structure.
Depth:
Number of bitplanes to use.
Width:
The width of the BitMap.
Height:
The height of the BitMap.
4. Allocate display memory for the BitMap:
for( loop=0; loop < Depth; loop++)
if( (my_bitmap.Planes[loop] = AllocRaster( Width,
Height )) == NULL )
{
/* PANIC! Not enough memory */
}
5. After you have allocated the display memory, it normally best to clear the
Bitplanes:
for( loop=0; loop < Depth; loop++)
BltClear(my_bitmap.Planes[loop], RASSIZE(Width, Height), 0);
6. Make sure the NewWindow's BitMap pointer is pointing to your BitMap
structure:
my_new_window.BitMap=&my_bitmap;
7. At last you can open the window:
my_window = OpenWindow( &my_new_window );
8. Do not forget to close the window, AND deallocate the display memory:
CloseWindow( my_window );
for( loop=0; loop < Depth; loop++)
if( my_bitmap.Planes[loop] )
FreeRaster( my_bitmap.Planes[loop], Width, Height );
2.9 MAKE YOUR OWN CUSTOM POINTER
Each window can have its individual pointer. When the window becomes active the
pointer can change image. This makes it easier for the user to see which window
is active, and can also give the user a hint about what the computer is doing.
For example, a wordprocessor can have a pointer that looks similar to a pencil,
and when the computer is busy, the pointer change to a little Zzz symbol.
If your window is going to use a "custom" pointer you need to:
1. Allocate and initialize a Sprite data structure.
2. Use the function SetPointer() to change the window's pointer.
When you are going to make a new image for your pointer, you first need to
sketch how it should look like. The pointer is actually a Sprite (See chapter
10 SPRITES for more information about Sprites), and can therefore be up to 16
pixels wide, and be as tall as you want. You may use 3 colours, and
transparent. (Since the pointer is a Sprite (no. 0) it can move between
different screens with different resolutions, without destroying the display.)
A nice "arrow" pointer (16 pixels wide, 16 lines high) may look something like
this:
0000000200000000 0: Transparent
0000002200000000 1: Red
0000023200000000 2: Black
0000231200000000 3: White
0002311200000000
0023111222222200
0231111133333320
2311111111111132
0211111111111112
0021111222221112
0002111200023112
0000211200023112
0000021200023112
0000002200023112
0000000200023112
0000000000022222
You now need to translate this into Sprite Data. Each line of the pointer will
be translated into two words of data. The first word represents the first
Bitplane, and the second word the second Bitplane. The idea is that if you want
colour 0 both Bitplane zero and one should be 0, if you want colour 1 Bitplane
zero should be 1 and Bitplane one 0 and so on:
Colour Bitplane One Bitplane Zero Since
------------------------------------------------------------
0 0 0 Binary 00 = Decimal 0
1 0 1 " 01 = " 1
2 1 0 " 10 = " 2
3 1 1 " 11 = " 3
The data for the pointer would then look like this:
Bitplane ZERO Bitplane ONE
0000 0000 0000 0000 0000 0001 0000 0000
0000 0000 0000 0000 0000 0011 0000 0000
0000 0010 0000 0000 0000 0111 0000 0000
0000 0110 0000 0000 0000 1101 0000 0000
0000 1110 0000 0000 0001 1001 0000 0000
0001 1110 0000 0000 0011 0001 1111 1100
0011 1111 1111 1100 0111 0000 1111 1110
0111 1111 1111 1110 1100 0000 0000 0011
0011 1111 1111 1110 0100 0000 0000 0001
0001 1110 0000 1110 0010 0001 1111 0001
0000 1110 0000 1110 0001 0001 0001 1001
0000 0110 0000 1110 0000 1001 0001 1001
0000 0010 0000 1110 0000 0101 0001 1001
0000 0000 0000 1110 0000 0011 0001 1001
0000 0000 0000 1110 0000 0001 0001 1001
0000 0000 0000 0000 0000 0000 0001 1111
The last step is to translate the binary numbers to base hexadecimal. Group the
binary number in four and translate it to Hexadecimal:
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7
1000 = 8
1001 = 9
1010 = A
1011 = B
1100 = C
1101 = D
1110 = E
1111 = F
The result will look like this:
ZERO: ONE:
------------
0000 0100
0000 0300
0200 0700
0600 0d00
0E00 1900
1E00 31FC
3FFC 60FE
7FFE c003
3FFE 4001
1E0E 21F1
0E0E 1119
060E 0919
020E 0519
000E 0319
000E 0119
0000 001F
Since the Amiga need to store the position of the pointer, the size etc, you
should also declare two empty words at the top, and two empty words at the
bottom of the Sprite data. These words will be initialized and maintained by
Intuition, so you do not need to bother about them.
A declaration and initialization of a nice arrow as Sprite data for a pointer
would therefore be: (A hexadecimal number as 3FFE will written in C be 0x3FFE.)
UWORD chip my_sprite_data[36]=
{
0x0000, 0x0000, /* Used by Intuition only. */
0x0000, 0x0100,
0x0000, 0x0300,
0x0200, 0x0700,
0x0600, 0x0D00,
0x0E00, 0x1900,
0x1E00, 0x31FC,
0x3FFC, 0x60FE,
0x7FFE, 0xC003,
0x3FFE, 0x4001,
0x1E0E, 0x21F1,
0x0E0E, 0x1119,
0x060E, 0x0919,
0x020E, 0x0519,
0x000E, 0x0319,
0x000E, 0x0119,
0x0000, 0x001F,
0x0000, 0x0000 /* Used by Intuition only. */
};
It is actually not so complicated once you get used to it, but to make the life
a bit easier I have written some utilities which will help you with translating
graphics to sprite data. See the TOOL drawer for more information.
The last step is to call the function SetPointer() which would look like this:
SetPointer( my_window, my_sprite_data, 16, 16, 0, -7);
my_window:
Pointer to the window.
my_sprite_data:
Pointer to the Sprite Data.
16:
Height.
16:
Width. (Must be 16 or less!)
0:
XOffset, left side. (Position of the Hot Spot)
-7:
YOffset, 7 lines down.
-"-
The "Hot Spot" is the pixel which should be the sensitive spot on the pointer.
On the default pointer it is on the top left side, but on our custom pointer it
should be on the left side (0), half way down (-7).
To restore the default pointer you simply call the function ClearPointer():
ClearPointer( my_window );
Since you are going to use graphics data it is important that the data is
placed in the Chip Memory. Chip Memory is the first 512 KB of RAM, and the
graphics routines in the Amiga demands that Sprite Data, as well as other
graphics data, is placed there. (The reason why is that the CPU on the Amiga
can reach the first 9MB of RAM, while the Blitter (a graphics co-processor)
only can reach the first 512 KB.
There will soon be a new Chip set for the Amiga 500 and 2000 which enables the
Blitter etc to reach the first 1 MB, but up to now the data MUST be placed
somewhere in the memory between $00000 to 7FFFF.)
If you are using Lattice C Compiler V5.0 or higher it is very simple. You only
need to place the little word "chip" in front of the data. Eg:
UWORD chip graphics_data[]={ ... };
On the Lattice C Compiler V4.0 you can compile the source with the added
command: "-acdb" which will load everything into the Chip Memory. Eg:
lc -acdb -Lm my_program.c
This will do both the lc1 and lc2 compilation, and it will also link the code
together with the standard math library. Everything is loaded into Chip Memory.
If you do not have one of these C compilers you will probably find out how to
do it in your manual. REMEMBER! If you do not tell the compiler to always put
the graphics in the Chip Memory you can end up with horrible bugs. It may
sometimes work, especially if you have an unexpanded Amiga, but it will
probably crash on an expanded Amiga.
2.10 FUNCTIONS
Here are some functions that are often used together with windows:
OpenWindow()
This function will open a window with the characteristics defined in the
NewWindow structure. It returns a pointer to a Window structure.
If you are going to use the Workbench screen, and it has been closed, it will
automatically reopen. If you on the other hand is going to connect the window
to a Custom screen, you need to open it yourself before calling the
OpenWindow() function.
Synopsis:
my_window = OpenWindow( my_new_window );
my_window:
struct Window *) Pointer to a Window structure or NULL if the window could not
be opened.
my_new_window:
(
struct NewWindow *) Pointer to a NewWindow structure which has been initialized
with your requirements.
CloseWindow()
This function will close a window you have previously opened. Remember that you
need to close all windows connected to a screen before you may close the
screen, and all opened windows must have been closed before your program quits.
Synopsis:
CloseWindow( my_window );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
MoveWindow()
This function will move a window. It has the same effect as if the user would
have moved the window by using the Drag Gadget.
Synopsis:
MoveWindow( my_window, delta_x, delta_y );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
delta_x:
(long) Deltamovement horizontally.
delta_y:
(long) Deltamovement vertically.
SizeWindow()
This function will change the size of the window as desired. It has the same
effect as if the user would have resized the window by using the Size Gadget.
Synopsis:
SizeWindow( my_window, delta_x, delta_y );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
delta_x:
(long) Number of pixels the horizontally size of the window will change.
delta_y:
(long) Number of pixels the vertically size of the window will change.
WindowToFront()
This function will put the window in front of all other windows.
Synopsis:
WindowToFront( my_window );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
WindowToBack()
This function will push the window behind all other windows.
Synopsis:
WindowToBack( my_window );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
SetWindowTitles()
This function allows you to change the window title after the window has been
opened.
Synopsis: SetWindowTitles( my_window, window_t, screen_t );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
window_t:
(char *) Pointer to a NULL-terminated string which will become the window's
title, or
0 : clear title bar, or
-1 : keep the old title.
screen_t:
(char *) Pointer to a NULL-terminated string which will become the window's
screen title, or
0 : clear title bar, or
-1 : keep the old title.
WindowLimits()
This function will change the maximum/minimum size limits of the window. Any
values which are set to 0 will remain unchanged.
Synopsis:
WindowLimits( my_window, min_w, min_h, max_w, max_h );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
min_w:
(long) Minimum width of the window.
min_h:
(long) Minimum height of the window.
max_w:
(long) Maximum width of the window.
max_h:
(long) Maximum height of the window.
SetPointer()
This function allows you to change the window's pointer.
Synopsis:
SetPointer( my_window, data, height, width, x, y );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
data:
(short *) Pointer to the Sprite data.
width:
(long) The width of the pointer. Less or equal to 16.
height:
(long) The height of the pointer. Can be any height.
x:
(long) The pointer's "Hot Spot" x position.
y:
(long) The pointer's "Hot Spot" y position.
ClearPointer()
This will remove the "custom" pointer, and replace it with Intuition's default
pointer.
Synopsis:
ClearPointer( my_window );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
ReportMouse()
You can call this function if you want the window to start/ stop reporting the
mouse position. (See chapter 8 IDCMP for more information about REPORTMOUSE.)
Synopsis:
ReportMouse( my_window, boolean );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
boolean:
(long) Set to TRUE if you want the window to start reporting mouse position,
else set to FALSE, and the window will stop reporting.
BeginRefresh()
This function will speed up your redrawing of the window. You should call this
function before you start to refresh the window, and only the parts that needs
to be redrawn are redrawn.
Synopsis:
BeginRefresh( my_window );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
EndRefresh()
This function will tell Intuition that you have finished with your redrawings.
IMPORTANT! If you receive a REFRESHWINDOW message, you must call the functions
BeginRefresh() and EndRefresh(), even if you do not want to redraw anything.
Synopsis:
EndRefresh( my_window );
my_window:
(struct Window *) Pointer to a Window structure which has previously been
initialized by an OpenWindow() call.
2.11 EXAMPLES
We have now looked at different types of windows, how to connect System
Gadgets, the steps to customize your pointer and much more. It is now again
time to look at some examples:
Example 1
This program will open a normal window which is connected to the Workbench
Screen. It will display it for 30 seconds, and then close it.
Example 2
This program will open a high resolution 16 colour Custom Screen and a normal
window which is connected to it. It will display it for 30 seconds, and then
close the Custom Screen and the window.
Example 3
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will automatically Activate
the window. It will display it for 30 seconds, and then close it. (Remember
that the Close Gadget does NOT close the window by itself, it will only inform
you that the user wants to close it. But in this example we will not listen to
what the user wants.)
Example 4
This program will open two normal windows which are connected to the Workbench
Screen. The windows will use all System Gadgets. It will display them for 30
seconds, and then close them.
Example 5
This program will open a Borderless window which is connected to the Workbench
Screen. It will display it for 30 seconds, and then quit.
Example 6
Same as Example 5 except that the window will also use all System Gadgets.
Example 7
This program will open three windows, two are normal and the third is a
Backdrop window. The windows will use all System Gadgets, except the Backdrop
window, which only can use the close-window gadget. After 30 seconds the
program quits. (Try to push either window 1 or 2 behind the Backdrop window.)
Example 8
This program will open a SuperBitMap window which is connected to the Workbench
Screen. Since it is a SuperBitMap we also make the window into a Gimmezerozero
window. The window will use all System Gadgets, and some boxes will be drawn.
It will display the window for 30 seconds, and then close it. (Shrink the
window, and then enlarge it again, and you will noticed that the lines are
still there!)
Example 9
This program will open a normal window with all system gadgets connected to it.
If you activate the window, the pointer will change shape into a "nice" arrow.
Example 10
This program will open a two normal windows with all system gadgets connected
to them. If the first window is Activated, the pointer will change shapes into
a Zzz symbol, if the second window is activated, the pointer will look like a
pistol.
GRAPHICS
3.1 INTRODUCTION
We have now looked at how to open different types of screens, and how to open
different types of windows connected to the screens etc. It is all very good,
but what would Intuition be without any graphics to display in the
screens/windows?
Intuition's main idea is to make the communication between the program and the
user as easy as possible. Graphics enables you to display the results that the
computer has calculated in an understandable way (a picture says more than...).
Graphics makes it also much easier to use the program, and can warn the user if
something dangerous is going to happen: It is very easy to press the wrong
button if you have got a question like "OK to erase disk?", but if there also
had been a picture showing a cross with the text "RIP" on, you would probably
have been a bit more careful.
There exist both a low- and a high-level way of making graphics. The low-level
approach (Graphics Primitives) is not described in this chapter since it is not
related to Intuition. The low-level graphics routines are very fast, but if you
are not careful they can trash menus etc. We will here concentrate our self on
the high-level approach which is supported by Intuition, and is a safe way of
drawing.
3.2 LINES TEXT PICTURES
Intuition gives you three different methods of making graphics:
- You can draw lines (Borders).
- Print text (IntuiText).
- Or you can directly print graphics images (Images).
3.3 BORDERS
Border has a bit misleading name since you are not limited to only draw
borders, you may draw any kind of shapes which is made out of connecting lines.
A Border structure may also be connected to other Border structures, so
everything which can be drawn with lines, can be drawn with Intuition's Border
structure.
3.3.1 THE BORDER STRUCTURE
When you want to draw lines you need to declare and initialize a Border
structure which look like this:
struct Border
{
SHORT LeftEdge, TopEdge;
SHORT FrontPen, BackPen, DrawMode;
SHORT Count;
SHORT *XY;
struct Border *NextBorder;
};
LeftEdge, TopEdge:
Start position of the lines.
FrontPen:
Colour register used to draw the lines.
BackPen:
This variable is for the moment unused.
DrawMode:
Must be either JAM1 or XOR. If the JAM1 flag is set, the colour specified
(FrontPen) will be used to draw the lines regardless what the background colour
is. The XOR flag makes the lines to be drawn with the binary complement of the
background colours.
Count:
The number of coordinates there is in the XY array. (See below for more
information.)
XY:
A pointer to an array of coordinates used to draw the lines. (See below for
more information.)
NextBorder:
A pointer to the next Border structure if there exist one, else NULL.
3.3.2 COORDINATES
If you want to draw this:
(10,10) (25,10)
*--------------*
| (35,12)
| *
| |
*---------*
(25,14) (35,14)
The array of coordinates would look like this:
SHORT my_points[]=
{
10,10, /* Start at position (10,10) */
25,10, /* Draw a line to the right to position (25,10) */
25,14, /* Draw a line down to position (25,14) */
35,14, /* Draw a line to the right to position (35,14) */
35,12 /* Finish of by drawing a line up to position (35,12) */
};
The array contains 5 pair of coordinates, so the variable Count should be set
accordingly. The entire Border structure would therefore look something like
this:
struct Border my_border=
{
0, 0, /* LeftEdge, TopEdge. */
3, /* FrontPen, colour register 3. */
0, /* BackPen, for the moment unused. */
JAM1, /* DrawMode, draw the lines with colour 3. */
5, /* Count, 5 pair of coordinates in the array. */
my_points, /* XY, pointer to the array with the */
/* coordinates. */
/* (Remember my_points == &my_points[0]) */
NULL /* NextBorder, no other Border structures */
/* comes after this one. */
};
3.4 HOW TO USE THE BORDER STRUCTURE
The Border structure is either used to draw lines in a screen or window, but
can also be used to draw lines connected to a Gadget, Requester or Menu. (See
chapter 4, 5 and 7 for more information about Gadgets, Requesters and Menus.)
If you want to connect a Border structure with a Gadget etc, you simply
initialize the Gadget structure with a pointer to the Border structure, and
Intuition will draw the lines for you. This will be explained later.
If you want to draw the lines in a screen or window you need to tell Intuition
that you want it to use the structure to make some lines. You do it by calling
the function DrawBorder():
Synopsis
: DrawBorder( rast_port, border, x, y );
rast_port:
(struct RastPort *) Pointer to a RastPort.
If the lines should be drawn in a window, and my_window is a pointer to that
window, you write:
my_window->RPort.
If the lines should be drawn in a Screen, and my_screen is a pointer to that
screen, you write:
my_screen->RastPort.
border:
(struct Border *) Pointer to a Border structure which has been initialized with
your requirements.
x:
(long) Number of pixels added to the x coordinates.
y:
(long) Number of lines added to the y coordinates.
A call to draw some lines using my_border structure would look something like
this:
DrawBorder( my_window->RPort, &my_border, 0, 0 );
If you have created a Border structure which, for example, draws a box, you can
draw several boxes at different places just by changing the LeftEdge, RightEdge
fields of the Border structure, or by changing the x, y fields in the function
call. This shows how versatile Intuition's high-level way of drawing is.
3.4 TEXT
Printing text in the Display is supported by the IntuiText structure. It is
quite similar to the Border structure, and is executed in the same way. The
only difference is that you need to tell Intuition what Font you want to use,
and what text to print.
3.4.1 THE INTUITEXT STRUCTURE
When you want to print text you need to declare and initialize a IntuiText
structure which look like this:
struct IntuiText
{
UBYTE FrontPen, BackPen;
UBYTE DrawMode;
SHORT LeftEdge;
SHORT TopEdge;
struct TextAttr *ITextFont;
UBYTE *IText;
struct IntuiText *NextText;
};
FrontPen:
Colour register used to draw the text with.
BackPen:
Colour register used to draw the background of the text.
DrawMode:
There exist three different way of printing the text:
JAM1 The colour specified (FrontPen) will be used to draw the text with, the
background is unchanged.
JAM2 The FrontPen colour will be used to draw the text with, the background is
drawn with the BackPen colour.
XOR The text is drawn with the the binary complement of the background.
LeftEdge, TopEdge:
Start position of the text.
ITextFont:
A pointer to a TextAttr structure which tells Intuition what font, size and
style etc to print the text with. Set to NULL if you want to use the default
font. (See below for more information.)
IText:
A pointer to a NULL-terminated string that should be printed.
NextText:
A pointer to the next IntuiText structure if there exist one, else write NULL.
3.4.2 FONTS
You can tell Intuition to print the text with a specific font/style. You only
need to declare and initialize a TextAttr structure, and give your IntuiText
structure a pointer to the TextAttr structure.
The TextAttr structure look like this:
struct TextAttr
{
STRPTR ta_Name;
UWORD ta_YSize;
UBYTE ta_Style
UBYTE ta_Flags;
};
We will for the moment only discuss how to access the ROM-fonts (the fonts
which are always available in ROM), and will wait with Disk-fonts (fonts which
your program can access from the disk).
There exist only one ROM-font for the moment, and that one is called Topaz. It
exist in two sizes, 64/32 and 80/40 (high/low-resolution) characters per line,
and can be printed in five different styles, normal, bold, italic, underlined
and extended,which can be combined as desired.
ta_Name:
Name of the font. Set it to "topaz.font" for the moment.
ta_YSize:
Font height. Can either be TOPAZ_SIXTY (64/32) or TOPAZ_EIGHTY (80/40).
ta_Style:
Style (normal, bold, underlined, italic and extended). Set the desired flags:
FS_NORMAL
No special style.
FSF_EXTENDED
Extended font, wider than normal.
FSF_ITALIC
Italic, slanted 1:2 to the right.
FSF_BOLD
Bold, thicker than normal.
FSF_UNDERLINED
Underlined, line under the baseline.
ta_Flags:
Preferences. Should for the moment be set to FPF_ROMFONT.
Here is an example on how you can print some text with underlined, italic
characters:
struct TextAttr my_font=
{
"topaz.font", /* Topaz font. */
TOPAZ_EIGHTY, /* 80/40 characters. */
FSF_ITALIC | FSF_UNDERLINED, /* Underlined italic chars. */
FPF_ROMFONT /* Exist in ROM. */
};
UBYTE my_text[]="This is the text that will be printed!";
struct IntuiText my_intui_text=
{
2, /* FrontPen, colour register 2. */
3, /* BackPen, colour register 3. */
JAM2, /* DrawMode, draw the characters with colour 2, */
/* on a colour 3 background. */
0, 0, /* LeftEdge, TopEdge. */
&my_font, /* ITextFont, use my_font. */
my_text, /* IText, the text that will be printed. */
/* (Remember my_text = &my_text[0].) */
NULL /* NextText, no other IntuiText structures are */
/* connected. */
};
3.4.3 HOW TO USE THE INTUITEXT STRUCTURE
The IntuiText structure is either used to print text in a screen or window, but
can also be used to print text connected to a Gadget, Menu or Requester. Same
as with drawing lines with the Border structure.
When you want to print text in a window/screen you simply call the function
PrintIText():
Synopsis
: PrintIText( rast_port, intui_text, x, y );
rast_port:
(struct RastPort *) Pointer to a RastPort.
If the text should be printed in a window, and my_window is a pointer to that
window, you write:
my_window->RPort.
If the text should be printed in a Screen, and my_screen is a pointer to that
screen, you write:
my_screen->RastPort.
intui_text:
(struct IntuiText *) Pointer to a IntuiText structure which has been
initialized with your requirements.
x:
(long) Number of pixels added to the x position of the characters.
y:
(long) Number of lines added to the y position of the characters.
A call to print some text using my_intui_text structure would look something
like this:
PrintIText( my_window->RPort, &my_intui_text, 0, 0 );
3.5 IMAGES
We have now looked at how to draw lines and print text. We will finish off by
looking at how to print a whole image directly. The procedure can be divided
into three steps:
1. Declare and initialize the data which should be drawn.
2. Declare and initialize an Image structure.
3. Call the function DrawImage() to draw the image.
3.5.1 IMAGE DATA
Intuition wants to have the image data structured into blocks of 16-bit memory
words (UWORD), organized into rectangular areas (BitPlanes). You may have up to
6 BitPlanes (4 if you are displaying the image on a high-resolution screen).
The colour of each pixel is determined by the binary number of the BitPlanes.
For example, to get a pixel with colour 6 on a screen with a Depth of 4,
BitPlane zero and three should be 0, and BitPlane one and two should be 1,
since the binary number 0110 is equal to the decimal number 6.
A little arrow can for example look like this: (1 BitPlane = 2 colours)
Image 16-Bit memory words Hexadecimal representation
------------------------------------------------------------
0001000 0001 0000 0000 0000 1 0 0 0
0011100 0011 1000 0000 0000 3 8 0 0
0111110 0111 1100 0000 0000 7 C 0 0
1111111 1111 1110 0000 0000 F E 0 0
0001000 0001 0000 0000 0000 1 0 0 0
0001000 0001 0000 0000 0000 1 0 0 0
0001000 0001 0000 0000 0000 1 0 0 0
0001000 0001 0000 0000 0000 1 0 0 0
Even if the Image only is 7 pixels wide, we needed to make the Image data 16
(bits) pixels wide, since Intuition wants the data ordered into 16-bit memory
words. (Of course, when we print it out we can tell Intuition that the image
should be only 7 pixels wide.)
Each group of four pixels is then translated into a hexadecimal value. See
table:
Binary => Hexadecimal
---------------------
0000 = 0
0001 = 1
0010 = 2
0011 = 3
0100 = 4
0101 = 5
0110 = 6
0111 = 7
1000 = 8
1001 = 9
1010 = A
1011 = B
1100 = C
1101 = D
1110 = E
1111 = F
A declaration and initialization of the data for the arrow image will therefore
look like this:
UWORD chip my_image_data[]=
{
0x1000, /* BitPlane ZERO */
0x3800,
0x7C00,
0xFE00,
0x1000,
0x1000,
0x1000,
0x1000
};
Since the image data is made out of one BitPlane, the arrow will be drawn in
colour 1, and the background in colour 0.
If the image is wider than 16 pixels you need more than one word per line. Here
is an image which is 20 pixels wide, and will therefore require two words per
line:
Image 16-Bit memory words (2 words)
---------------------------------------------------------------
11111111111111111111 1111 1111 1111 1111 1111 0000 0000 0000
00111110000001111100 0011 1110 0000 0111 1100 0000 0000 0000
00001111100111110000 0000 1111 1001 1111 0000 0000 0000 0000
00111110000001111100 0011 1110 0000 0111 1100 0000 0000 0000
11111111111111111111 1111 1111 1111 1111 1111 0000 0000 0000
We translate the binary numbers into hexadecimal, and we end up with:
UWORD chip my_image_data[]=
{
0xFFFF, 0xF000, /* BitPlane ZERO */
0x3E07, 0xC000,
0x0F9F, 0x0000,
0x3E07, 0xC000,
0xFFFF, 0xF000
};
If we want more than two colours we need more than one BitPlane. A four-colour
face can look something like this:
003333300000 0: Blue (Normal Workbench colours)
033333330000 1: White
332232233000 2: Black
323333323000 3: Orange
331131133000
331131133000
331232133000
331232133000
333333333000
332333233000
033222330000
033333330000
003333300000
We translate it into 16-Bit memory words organized into two Bitplanes (Two
BitPlanes = 4 colours):
Colour Bitplane ONE Bitplane ZERO SINCE
------------------------------------------------------
0 0 0 00 (b) = 0 (d)
1 0 1 01 (b) = 1 (d)
2 1 0 10 (b) = 2 (d)
3 1 1 11 (b) = 3 (d)
Bitplane ONE Bitplane ZERO
-----------------------------------------
0011 1110 0000 0000 0011 1110 0000 0000
0111 1111 0000 0000 0111 1111 0000 0000
1111 1111 1000 0000 1100 1001 1000 0000
1111 1111 1000 0000 1011 1110 1000 0000
1100 1001 1000 0000 1111 1111 1000 0000
1100 1001 1000 0000 1111 1111 1000 0000
1101 1101 1000 0000 1110 1011 1000 0000
1101 1101 1000 0000 1110 1011 1000 0000
1111 1111 1000 0000 1111 1111 1000 0000
1111 1111 1000 0000 1101 1101 1000 0000
0111 1111 0000 0000 0110 0011 0000 0000
0111 1111 0000 0000 0111 1111 0000 0000
0011 1110 0000 0000 0011 1110 0000 0000
Each group of four pixels is then translated into a hexadecimal value:
Bitplane ONE Bitplane ZERO
-----------------------------------
3 E 0 0 3 E 0 0
7 F 0 0 7 F 0 0
F F 8 0 C 9 8 0
F F 8 0 B E 8 0
C 9 8 0 F F 8 0
C 9 8 0 F F 8 0
D D 8 0 E B 8 0
D D 8 0 E B 8 0
F F 8 0 F F 8 0
F F 8 0 D D 8 0
7 F 0 0 6 3 0 0
7 F 0 0 7 F 0 0
3 E 0 0 3 E 0 0
A declaration and initialization of the data for the face image will therefore
look like this:
USHORT chip my_image_data[]=
{
0x3E00, /* Bitplane ZERO */
0x7F00,
0xC980,
0xBE80,
0xFF80,
0xFF80,
0xEB80,
0xEB80,
0xFF80,
0xDD80,
0x6300,
0x7F00,
0x3E00,
0x3E00, /* Bitplane ONE */
0x7F00,
0xFF80,
0xFF80,
0xC980,
0xC980,
0xDD80,
0xDD80,
0xFF80,
0xFF80,
0x7F00,
0x7F00,
0x3E00
};
Remember that all Image Data MUST be in Chip Memory!
3.5.2 THE IMAGE STRUCTURE
The Image structure look like this:
struct Image
{
SHORT LeftEdge, TopEdge;
SHORT Width, Height, Depth;
SHORT *ImageData;
UBYTE PlanePick, PlaneOnOff;
struct Image *NextImage;
};
LeftEdge:
X position of the Image.
TopEdge:
Y position of the Image.
Width:
The actual width of the Image.
Height:
The height of the Image.
Depth:
Number of Bitplanes used for the Image.
ImageData:
A pointer to the Image data.
PlanePick:
Which Bitplanes of the displaying element should be changed/affected by the
Image. (See below for more information.)
PlaneOnOff:
What should happen to the Bitplanes of the displaying element that were not
affected. Should they be filled with 1's or 0's. (See below for more
information.)
NextImage:
A pointer to the next Image structure if there exist one, else NULL.
3.5.3 PLANEPICK
The advantages with the PlanePick/PlaneOnOff fields are that you can print the
Image into a display of any depth, print the same Image in different colours,
and it will eliminate unnecessary memory-waste when using coloured Images.
PlanePick tells Intuition which Bitplanes of the display to be affected by the
Image. For every "picked" plane, the next successive Bitplane of the image is
printed there. For example:
If we set PlanePick to 1, Bitplane zero would be affected. If we then printed
the arrow Image, we would get the arrow drawn with colour 1, and the background
drawn with colour 0.
If we had instead set PlanePick to 2, Bitplane one would have been affected,
which would result in that the arrow would have been drawn with colour 2, and
the background still drawn with colour 0.
If our Image would consist of several Bitplanes, the lowest picked plane would
be affected by the lowest Bitplane, and so on. If we take our face Image for
example, and we want to draw it with colour 3, 2 1 and 0, we want to affect
Bitplane zero and BitPlane one of the display. We would therefore need to set
PlanePick to 3, see table:
Bitplane to affect PlanePick
------------------------------
No planes affected 0000 = 0
Plane 0 0001 = 1
Plane 1 0010 = 2
Plane 1 and 0 0011 = 3
Plane 2 0100 = 4
Plane 2 and 0 0101 = 5
Plane 2 and 1 0110 = 6
Plane 2, 1 and 0 0111 = 7
Plane 3 1000 = 8
Plane 3 and 0 1001 = 9
Plane 3 and 1 1010 = A
and so on...
If we want to draw it with colour 5, 4, 1 and 0, we want to affect Bitplane two
and zero:
(000=colour 0, 001=colour 1, 100=colour 4, 101=colour 5)
^ ^ ^ ^ ^ ^ ^ ^
210 210 210 210 (BitPlanes)
We would then set PlanePick to 5 (0101).
3.5.4 PLANEONOFF
PlaneOnOff decides what should happen to the Bitplanes of the displaying
element that were not affected by PlanePick. Should these Bitplanes be filled
with 1's or 0's.
For example, if we want to print the little arrow in colour 5 and the
background in colour 1 the pixels should have the values 0001 (colour 1) and
0101 (colour 5). We want the Image to affect Bitplane two, so PlanePick is set
to 4 (0100). But we also want Bitplane zero to be filled with 1's, so
PlaneOnOff is set to 1 (0001).
With help of PlanePick and PlaneOnOff you can even print filled rectangles
without any Image data. You only need to set Width and Height as desired, and
then set Depth to 0 (no Bitplanes), PlanePick to 0000 (no Bitplanes should be
used) and PlaneOnOff to the colour you want.
3.5.5 HOW TO USE THE IMAGE STRUCTURE
The Image structure is either used to print images in a screen or window, but
can also be used to print images connected to a Gadget, Menu or Requester. Same
as Intuition's other Graphics structures.
When you want to print an image in a window/screen you simply call the function
DrawImage():
Synopsis
: DrawImage( rast_port, image, x, y );
rast_port:
(struct RastPort *) Pointer to a RastPort.
If the images should be drawn in a window, and my_window is a pointer to that
window, you write:
my_window->RPort.
If the images should be drawn in a Screen, and my_screen is a pointer to that
screen, you write:
my_screen->RastPort.
image:
(struct Image *) Pointer to an Image structure which has been initialized with
your requirements.
x:
(long) Number of pixels added to the x position of the image.
y:
(long) Number of lines added to the y position of the image.
A call to print an image using my_image structure would look something like
this:
DrawImage( my_window->RPort, &my_image, 0, 0 );
3.6 FUNCTIONS
Here are the three functions you use when you want to draw
lines/characters/images into a RastPort (Screen/Window):
DrawBorder()
This function draws the specified Borders into a RastPort (Screen/Window).
Synopsis: DrawBorder( rast_port, border, x, y );
rast_port:
(struct RastPort *) Pointer to a RastPort.
If the lines should be drawn in a window, and my_window is a pointer to that
window, you write:
my_window->RPort.
If the lines should be drawn in a Screen, and my_screen is a pointer to that
screen, you write:
my_screen->RastPort.
border:
(struct Border *) Pointer to a Border structure which has been initialized with
your requirements.
x:
(long) Number of pixels added to the x coordinates.
y:
(long) Number of lines added to the y coordinates.
PrintIText()
This function prints text into a RastPort (Screen/Window).
Synopsis: PrintIText( rast_port, intui_text, x, y );
rast_port:
(struct RastPort *) Pointer to a RastPort.
If the text should be printed in a window, and my_window is a pointer to that
window, you write:
my_window->RPort.
If the text should be printed in a Screen, and my_screen is a pointer to that
screen, you write:
my_screen->RastPort.
intui_text:
(struct IntuiText *) Pointer to a IntuiText structure which has been
initialized with your requirements.
x:
(long) Number of pixels added to the x position of the characters.
y:
(long) Number of lines added to the y position of the characters.
DrawImage()
This function draws the specified images into a RastPort (Screen/Window).
Synopsis: DrawImage( rast_port, image, x, y );
rast_port:
(struct RastPort *) Pointer to a RastPort.
If the images should be drawn in a window, and my_window is a pointer to that
window, you write:
my_window->RPort.
If the images should be drawn in a Screen, and my_screen is a pointer to that
screen, you write:
my_screen->RastPort.
image:
(struct Image *) Pointer to an Image structure which has been initialized with
your requirements.
x:
(long) Number of pixels added to the x position of the image.
y:
(long) Number of lines added to the y position of the image.
3.7 EXAMPLES
Here are some examples on how to draw lines (Border), print text (IntuiText)
and draw pictures (Image):
Example 1
This program will open a normal window which is connected to the Workbench
Screen. We will then draw a strange line with help of Intuition's Border
structure.
Example 2
This program will open a normal window which is connected to the Workbench
Screen. We will then draw two rectangles with different colours. This shows how
you can link Border structures to each other in order to get the desired
effects.
Example 3
This program will open a normal window which is connected to the Workbench
Screen. We will then print a text string with help of Intuition's IntuiText
structure.
Example 4
Same as Example 3 except that the text will be printed with underlined italic
characters.
Example 5
This program will open a normal window which is connected to the Workbench
Screen. We will then draw the little nice arrow we talked so much about.
Example 6
Same as Example 5 except that we will draw it several times in different
colours. This shows how PlanePick/PlaneOnOff works.
Example 7
This program will open a normal window which is connected to the Workbench
Screen. We will then draw the nice 4 colour face that was described in chapter
3.5 IMAGES.
Example 8
This program will open a normal window which is connected to a 16-colour Custom
screen. In the window we will draw the famous AMIGA-logo.
GADGETS
4.1 INTRODUCTION
In this chapter we will look at how the user can communicate with the program.
All programs which use Intuition should, if possible, be controlled by a mouse,
since it is the most commonly used input device. Intuition's Gadgets will play
a big role here.
A gadget can be a "button" which the user can click on, but it can also be a
small knob which can be dragged (like a volume control on a radio). A gadget
can even be a box where the user can enter a text string or a value. The
advantages of using gadgets are almost uncountable. They are very well
supported by Intuition which means that your program hardly needs to do
anything, but still have an outstanding user interface which is both easy to
understand as well as use.
4.2 DIFFERENT TYPES OF GADGETS
There exist two types of gadgets: System gadgets, which we already have
discussed in chapter 2.3 SYSTEM GADGETS, and Custom gadgets. For every window
System gadgets always look the same, and are always placed in the same places.
Custom Gadgets, however, can be placed wherever you want, and it is you who
decide what they should look like.
4.3 CUSTOM GADGETS
There exist four different types of Custom gadgets:
- Boolean gadget
On/Off (True/False) button.
- Proportional gadget
A small knob which can be moved around inside a container.
- String gadgets
Gadget which enables the user to enter a string.
- Integer gadget
Same as the String gadget, except that the user can only enter integer numbers.
4.3.1 GRAPHICS FOR CUSTOM GADGETS
You can render the gadget with help of the high-level graphics utilities which
are supported by Intuition (See chapter 3 GRAPHICS for more information). You
can render the gadget with help of a Border structure, or an Image structure.
You can even have a different rendering when the gadget is selected,
highlighted.
It is of course possible to open gadgets with no rendering at all. The Drag
gadget (System gadget) is a good example.
4.3.2 POSITION
You can position the gadget anywhere on the display. The position is normally
relative to the top left corner of the displaying element (Window, Requester
etc). If you want you can position the gadget relative to some other sides than
the top left corner:
If you want the gadget to be placed 10 pixels out and 20 lines down from the
top left corner of a window, you set LeftEdge to 10, and TopEdge to 20.
(LeftEdge etc are elements in the Gadget structure which is described later in
the chapter.)
If you on the other hand want the gadget to always be 20 pixels above the
bottom border of the window, and 10 pixels to the left of the right border, you
set LeftEdge to -10 and TopEdge to -20 together with the Flags GRELRIGHT and
GRELBOTTOM. (More about this later.)
4.3.3 SIZE
You decide the width and height of the gadget (the select box of the gadget) by
setting the Width and Height variables as desired.
If you set the Height to 25, the gadget will be 25 lines high.
If you on the other hand set the Height to -25 and you set the GRELHEIGHT flag,
the gadget will always be 25 lines smaller than the containing element (window
etc).
Same applies for the Width. If you set the Width to 50, the gadget will always
be 50 pixels wide.
If you on the other hand set the Width to be -50 and you set the flag
GRELWIDTH, the gadget will always be 50 pixels smaller than the containing
element.
4.4 INITIALIZE A CUSTOM GADGET
When you want to use a Custom gadget you need to declare and initialize a
Gadget structure which look like this:
struct Gadget
{
struct Gadget *NextGadget;
SHORT LeftEdge, TopEdge, Width, Height;
USHORT Flags;
USHORT Activation;
USHORT GadgetType;
APTR GadgetRender;
APTR SelectRender;
struct IntuiText *GadgetText;
LONG MutualExclude;
APTR SpecialInfo;
USHORT GadgetID;
APTR UserData;
}
NextGadget:
A pointer to the next gadget in the list if there exist one, else NULL.
LeftEdge, TopEdge:
Position of the gadget's select box relative to the displaying element.
Width, Height:
Width and height of the gadget's select box.
Flags:
You must set one of the following four highlighting flags: (The gadget is
highlighted when it is selected)
GADGHCOMP: Complement the colours of all pixels in the gadget's select box.
GADGHBOX: Draw a box around the the gadget's select box.
GADGHIMAGE: Display an alternative Image/Border.
GADGHNONE: No highlighting.
If the gadget should be rendered as an Image set the flag GADGIMAGE, otherwise
(render it with a Border structure, or no rendering at all) clear this flag.
If you want the position and/or size of the gadget to be relative to the size
of the displaying element, set the desired flags:
GRELBOTTOM: TopEdge is used as an offset relative to the bottom of the
displaying element, instead of an offset relative to the top of the displaying
element.
GRELRIGHT: LeftEdge is used as an offset relative to the right edge of the
displaying element, instead of an offset relative to the left edge of the
displaying element.
GRELWIDTH: Width describes an increment to the width of the displaying
element, instead of describing the absolute width of the gadget.
GRELRIGHT: Height describes an increment to the height of the displaying
element, instead of describing the absolute height of the gadget.
If this gadget is a toggle-select gadget (see Activation flags) you can set the
SELECTED flag, and the gadget will be selected and highlighted when opened. If
not, the gadget will be unselected and non-highlighted when opened.
You can also examine this field to see if the SELECTED flag is set or not. If
it is set, the gadget is selected, else it is unselected.
If you want that the gadget should be disabled when opened, you set the flag
GADDISABLED. Your program can later change this by calling the functions
OnGadget() (enables the gadget) and OffGadget() (disables the gadget).
Activation:
Set the flags for the desired effects: (More about these later...)
GADGIMMEDIATE: If you want your program to know immediately when the user
selects this gadget, you should set this flag.
RELVERIFY: If you want your program to receive a message when the user
releases the gadget and the pointer is still inside the gadget's select box,
you should set this flag.
FOLLOWMOUSE: Set this flag if you want your program to receive mouse
positions every time the user moves the mouse while this gadget is selected.
TOGGLESELECT: Each time the user selects this gadget, the on/off state of the
gadget (as well as the image) is toggled. Your program can later check the
status of the gadget by examining the SELECTED bit in the Flags field.
BOOLEXTEND: Set this flag if your gadget has a BoolInfo structure connected
to it.
If your gadget is connected to a window you can set the following flags in
order to change the size of the window's borders. (You can then put the gadget
there.):
RIGHTBORDER: The width of the window's right border is calculated with help
of the gadget's position and width.
LEFTBORDER: The width of the window's left border is calculated with help of
the gadget's position and width.
TOPBORDER: The height of the window's top border is calculated with help of
the gadget's position and height.
BOTTOMBORDER: The height of the window's bottom border is calculated with help
of the gadget's position and height.
If this gadget is connected to a requester you can set the ENDGADGET flag. The
requester will only go away when a gadget with the ENDGADGET flag has been
selected. (See chapter 5 REQUESTERS for more information about gadgets
connected to requesters.)
Intuition will only care about these flags if the gadget is a String/Integer
gadget:
STRINGRIGHT: Set this flag if you want the characters in the string to be
right-justified.
STRINGCENTER: Set this flag if you want the characters in the string to be
center-justified. (The default is left-justified.)
LONGINT: Set this flag if you want that the user should only be able to
enter a 32-bit signed integer value.
ALTKEYMAP: Set this flag if you want to use an alternative keymap. Remember
to give the AltKeyMap pointer in the StringInfo structure a pointer to the
keymap.
GadgetType: You must set one of the following three flags:
BOOLGADGET: Set this flag if you want a Boolean gadget.
STRGADGET: Set this flag if you want a String/Integer gadget. If you want
an Integer gadget you also need to set the Activation flag LONGINT.
PROPGADGET: Set this flag if you want a Proportional gadget.
The following two flags are only for gadgets connected to Gimmezerozero windows
and requesters.
GZZGADGET: If the gadget is connected to a Gimmezerozero window and you
have set this flag, the gadget will be put in the outer window, and will not
destroy any drawings etc in the inner window.
REQGADGET: Set this flag if the gadget is connected to a requester.
GadgetRender:
A pointer to an Image or Border structure (See chapter 3 GRAPHICS for more
information) which will be used to render the gadget. (If you supply a pointer
to an Image structure you need to set the Flags variable to GADGIMAGE.) Set it
to NULL if you do not want to supply the gadget with any graphics.
SelectRender:
A pointer to an alternative Image or Border structure which will be used when
the gadget is highlighted. Remember to set the GADGHIMAGE bit in the Flags
variable if you want to use an alternative Image/Border. (GadgetRender and
SelectRender must point to the same type of data. If you have specified that
you want to use an Image for the GadgetRender (GADGIMAGE), SelectRender must
then also point to an Image structure.)
GadgetText:
A pointer to an IntuiText structure (See chapter 3 GRAPHICS for more
information) which will be used to print some text in the gadget. Set it to
NULL if you do not want any text connected to your gadget.
MutualExclude:
This field represent the first 32 gadgets in the list. If this gadget is
selected, all specified gadgets in the MutualExclude field are deselected
automatically. For example, if you want that gadget number 0, 2, 5 and 8 should
be deselected (mutual excluded) when this gadget is selected, the MutualExclude
field should be set to 293. ( 293(d) == 100100101(b) )
Remember, the mutual exclude works only with toggle-select gadgets.
SpecialInfo:
If the gadget is a Proportional gadget you should here give Intuition a pointer
to a PropInfo structure, or if the gadget is a String (Integer) gadget you
should give Intuition a pointer to a StringInfo structure.
If the gadget is a Boolean gadget you can connect a BoolInfo structure which
will place a mask on the gadget's select box. (See below for more information.)
GadgetID
This variable is left for your own use. Intuition ignores this field.
UserData:
A pointer to any structure you may want to connect to the gadget. Intuition
ignores this field.
4.5 BOOLEAN GADGET
If you want a Boolean gadget you should declare and initialize the Gadget
structure something like this:
struct my_gadget=
{
NULL, /* NextGadget, no more gadgets in the list. */
40, /* LeftEdge, 40 pixels out. */
20, /* TopEdge, 20 lines down. */
60, /* Width, 60 pixels wide. */
20, /* Height, 20 pixels lines high. */
GADGHCOMP, /* Flags, when this gadget is highlighted, */
/* the gadget will be rendered in the */
/* complement colours: */
/* (Colour 0 (00) will become colour 3 (11) */
/* (Colour 1 (01) - " - 2 (10) */
/* (Colour 2 (10) - " - 1 (01) */
/* (Colour 3 (11) - " - 0 (00) */
GADGIMMEDIATE| /* Activation, our program will receive a */
RELVERIFY, /* message when the user has selected this */
/* gadget, and when the user has released */
/* it. */
BOOLGADGET, /* GadgetType, a Boolean gadget. */
&my_border, /* GadgetRender, a pointer to our Border */
/* structure. */
NULL, /* SelectRender, NULL since we do not */
/* supply the gadget with an alternative */
/* image. (We complement the colours */
/* instead.) */
&my_text, /* GadgetText, a pointer to our IntuiText */
/* structure. */
NULL, /* MutualExclude, no mutual exclude. */
NULL, /* SpecialInfo, no BoolInfo connected to it. */
0, /* GadgetID, no id. */
NULL /* UserData, no user data connected to the */
/* gadget. */
};
It is possible to connect a mask to a Boolean gadget. In that case the gadget
would only be selected when the user clicks inside the selected (masked) area,
and only that area would be highlighted. If you want to connect a mask to a
Boolean gadget you need to declare and initialize a BoolInfo structure together
with its mask.
The BoolInfo structure looks like this:
struct BoolInfo
{
USHORT Flags;
UWORD *Mask;
ULONG Reserved;
};
Flags:
There exists only one flag for the moment: BOOLMASK.
Mask:
Pointer to the binary mask. (The width and height of the mask must be the same
as the width and height of the select box.)
Reserved:
This field is reserved and should therefore be set to 0.
The binary mask is built up as an Image plane. Only the selected (1's) parts of
the mask will be sensitive and highlighted.
A mask for a gadget with the width of 16 pixels, and the height of 8 pixels can
look something like this: (Only the inner part of the select box will be
sensitive and highlighted.)
Mask 16-Bit memory words Hexadecimal
------------------------------------------------------
0000001111000000 0000 0011 1100 0000 03C0
0000111111110000 0000 1111 1111 0000 0FF0
0011111111111100 0011 1111 1111 1100 3FFC
1111111111111111 1111 1111 1111 1111 FFFF
1111111111111111 1111 1111 1111 1111 FFFF
0011111111111100 0011 1111 1111 1100 3FFC
0000111111110000 0000 1111 1111 0000 0FF0
0000001111000000 0000 0011 1100 0000 03C0
The mask would in this case be declared/initialized like this:
UWORD my_mask[]=
{
0x03C0,
0x0FF0,
0x3FFC,
0xFFFF,
0xFFFF,
0x3FFC,
0x0FF0,
0x03C0
};
See Example6 for more information about the BoolInfo structure.
4.6 STRING/INTEGER GADGET
String and Integer gadgets are a bit more complicated to declare since you need
to supply the Gadget structure with a StringInfo structure. However, String and
Integer gadgets allow the user to enter a string or an integer value without
much effort from your side. Intuition takes care of most of the work, and you
almost only need to decide how long and where the string gadget should be.
4.6.1 STRINGINFO STRUCTURE
The StringInfo structure look like this:
struct StringInfo
{
UBYTE *Buffer;
UBYTE *UndoBuffer;
SHORT BufferPosition;
SHORT MaxChars;
SHORT DispPos;
SHORT UndoPos;
SHORT NumChars;
SHORT DispCount;
SHORT CLeft, CTop;
struct Layer *LayerPtr;
LONG LongInt;
struct KeyMap *AltKeyMap;
};
Buffer:
A pointer to a NULL-terminated string.
UndoBuffer:
A pointer to a NULL-terminated string which is used by Intuition to store an
undo string. This must be at least as long as the Buffer string. When the user
selects this gadget Intuition makes a copy of the Buffer string which will be
copied back if the user presses AMIGA + Q. Since only one String/Integer gadget
can be active at a time several String/Integer gadgets can use the same undo
string.
MaxChars:
The maximum number of characters which may be entered. (Number of characters in
the buffer + the NULL '\0' sign.)
BufferPos:
Cursor position in the buffer string.
DispPos:
Position of the first character which is displayed.
These variables are initialized and maintained by Intuition:
UndoPos:
Cursor position in the undo string.
NumChars:
Current number of characters in the buffer.
DispCount:
Current number of visible characters in the container.
CLeft, CTop:
Top left offset of the container.
LayerPtr:
Pointer to the Layer structures.
LongInt:
If this is an Integer gadget you can examine the value here to find out what
the user has entered.
AltKeyMap:
A pointer to an alternative keymap. (Remember to set the flag ALTKEYMAP in the
Activation field.)
4.6.2 INITIALIZE A STRING/INTEGER GADGET
This is an example of how you can initialize a string gadget:
UBYTE my_buffer[50];
UBYTE my_undo_buffer[50];
struct StringInfo my_string_info=
{
my_buffer, /* Buffer, pointer to a NULL-terminated s. */
my_undo_buffer, /* UndoBuffer, pointer to a NULL- */
/* terminated string. (Remember my_buffer */
/* is equal to &my_buffer[0]) */
0, /* BufferPos, initial position of the */
/* cursor. */
50, /* MaxChars, 49 characters + NULL-sign. */
0, /* DispPos, first character in the string */
/* should be first character in the */
/* display. */
/* Intuition initializes and maintains these variables: */
0, /* UndoPos */
0, /* NumChars */
0, /* DispCount */
0, 0, /* CLeft, CTop */
NULL, /* LayerPtr */
NULL, /* LongInt */
NULL, /* AltKeyMap */
};
struct Gadget my_gadget=
{
NULL, /* NextGadget, no more gadgets in the list. */
68, /* LeftEdge, 68 pixels out. */
30, /* TopEdge, 30 lines down. */
198, /* Width, 198 pixels wide. */
8, /* Height, 8 pixels lines high. */
GADGHCOMP, /* Flags, draw the select box in the */
/* complement colours. Note: it is actually */
/* only the cursor which will be drawn in */
/* the complement colours (yellow). If you */
/* set the flag GADGHNONE the cursor will */
/* not be highlighted, and the user will */
/* therefore not be able to see it. */
GADGIMMEDIATE| /* Activation, our program will receive a */
RELVERIFY, /* message when the user has selected this */
/* gadget, and when the user has released */
/* it. */
STRGADGET, /* GadgetType, a String gadget. */
&my_border, /* GadgetRender, a pointer to our Border */
/* structure. */
NULL, /* SelectRender, NULL since we do not */
/* supply the gadget with an alternative */
/* image. */
&my_text, /* GadgetText, a pointer to our IntuiText */
/* structure. */
NULL, /* MutualExclude, no mutual exclude. */
&my_string_info,/* SpecialInfo, a pointer to a StringInfo */
/* structure. */
0, /* GadgetID, no id. */
NULL /* UserData, no user data connected to the */
/* gadget. */
};
The only difference between declaring and initializing a String gadget and an
Integer gadget, is that when you initialize an Integer gadget you also need to:
1. Set the flag LONGINT in the Activation field.
2. Copy an integer string into the buffer string. eg: strcpy( my_buffer, "0" );
4.6.3 USING A STRING/INTEGER GADGET
Once you have declared and initialized the appropriate structures Intuition
takes care of everything else. While the user is entering a string he/she can
even use some special keys:
------------------------------------------------------------
| <- Moves the cursor to the left. |
| -> Moves the cursor to the right. |
| SHIFT and <- Moves the cursor to the beginning of the |
| string. |
| SHIFT and -> Moves the cursor to the end of the string. |
| BACKSPACE Deletes the character to the left of the |
| cursor. |
| DEL Deletes the character under the cursor. |
| AMIGA and Q Undo the last changes of the string. |
| AMIGA and X Clears the buffer string. |
| RETURN Releases the gadget. If we have set the |
| activation flag RELVERIFY we will receive |
| a message telling us that the user has |
| finished. |
------------------------------------------------------------
4.7 PROPORTIONAL GADGET
A proportional gadget is roughly a knob which can be moved horizontally,
vertically or both inside a container. It can be like a volume control on a
radio, or it can be used to show the user how much more data there exist in the
file etc.
4.7.1 PROPINFO STRUCTURE
The PropInfo structure look like this:
struct PropInfo
{
USHORT Flags;
USHORT HorizPot;
USHORT VertPot;
USHORT HorizBody;
USHORT VertBody;
USHORT CWidth;
USHORT CHeight;
USHORT HPotRes, VPotRes;
USHORT LeftBorder;
USHORT TopBorder;
};
Flags:
You normally should set one or both of the following two bits:
FREEHORIZ Set this bit if you want the user to be able to move the knob
horizontally.
FREEVERT Set this bit if you want the user to be able to move the knob
vertically.
AUTOKNOB Set this bit if you want that the size of the knob to be
controlled by Intuition. (HorizBody and VertBody affects the size of the
Autoknob.)
- If you want to use Intuition's Autoknob you should give GadgetRender a
pointer to an Image structure. (You do not need to initialize the Image
structure since Intuition takes care of it.)
- If you on the other hand would like to use your own knob image, you give
GadgetRender a pointer to your Image structure, which you have initialized
yourself.
PROPBORDERLESS Set this bit if you do not want any border around the container.
KNOBHIT This is a flag which is set by Intuition if this gadget is
selected.
HorizPot:
This variable contains the actual (horizontally) proportional value. If the
user has moved the knob 25% to the right, HorizPot is 25% of MAXPOT (0xFFFF).
(0xFFFF * 0.25 = 0x3FFF)
VertPot:
Same as HorizPot except that this is the
vertically proportional value.
HorizBody:
Describes how much HorizPot should change every time the user clicks inside the
container. If the volume of a melody can be between 0-63 (64 steps), HorizPot
should change 1/64 each time. The HorizBody should therefore be initialized to:
1/64 * MAXBODY (0xFFFF) == 3FF
HorizBody describes also how much the user can see/use of the entire data. For
example, if you have a list of 32 file names, and the user only can see 8 names
at one time (25%), the knob (AUTOKNOB) should fill 25% of the container.
HorizBody should in this case be initialized to:
MAXBODY * 8 / 32 (25% of 0xFFFF) == 3FFFF
VertBody:
Same as HorizBody except that it affects VertPot, and the vertical size of the
knob (AUTOKNOB).
These variables are initialized and maintained by Intuition:
CWidth:
Width of the container.
CHeight:
Height of the container.
HPotRes, VPotRes:
Pot increments.
LeftBorder:
Position of the container's left border.
TopBorder:
Position of the container's top border.
4.7.2 INITIALIZE A PROPORTIONAL GADGET
This is an example of how you can initialize a proportional gadget which can,
for example, be used to change the volume of a melody (64 positions):
/* We need to declare an Image structure for the knob, but */
/* since Intuition will take care of the size etc of the */
/* knob, we do not need to initialize the Image structure: */
struct Image my_image;
struct PropInfo my_prop_info=
{
FREEHORIZ| /* Flags, the knob should be moved */
AUTOKNOB, /* horizontally, and Intuition should take */
/* care of the knob image. */
0, /* HorizPot, start position of the knob. */
0, /* VertPot, 0 since we will not move the */
/* knob vertically. */
MAXBODY * 1/64, /* HorizBody, 64 steps. */
0, /* VertBody, 0 since we will not move the */
/* knob vertically. */
/* These variables are initialized and maintained by */
/* Intuition: */
0, /* CWidth */
0, /* CHeight */
0, 0, /* HPotRes, VPotRes */
0, /* LeftBorder */
0 /* TopBorder */
};
struct Gadget my_gadget=
{
NULL, /* NextGadget, no more gadgets. */
80, /* LeftEdge, 80 pixels out. */
30, /* TopEdge, 30 lines down. */
200, /* Width, 200 pixels wide. */
12, /* Height, 12 pixels lines high. */
GADGHCOMP, /* Flags, no highlighting. */
GADGIMMEDIATE| /* Activation, our program will receive a */
RELVERIFY, /* message when the user has selected this */
/* gadget, and when the user has released */
/* it. */
PROPGADGET, /* GadgetType, a Proportional gadget. */
&my_image, /* GadgetRender, a pointer to our Image */
/* structure. (Intuition will take care */
/* of the knob image. See chapter 3 */
/* GRAPHICS for more information about */
/* images.) */
NULL, /* SelectRender, NULL since we do not */
/* supply the gadget with an alternative */
/* image. */
&my_text, /* GadgetText, pointer to a IntuiText */
/* structure. */
NULL, /* MutualExclude, no mutual exclude. */
&my_prop_info, /* SpecialInfo, pointer to a PropInfo */
/* structure. */
0, /* GadgetID, no id. */
NULL /* UserData, no user data connected to */
/* the gadget. */
};
4.8 MONITORING THE GADGETS
Once you have decided which gadgets to use and what they should look like, it
is time to decide what information they should send to your program. You need
to decide if they should send a message when the user has selected them, or
when the user has released them etc. All this work with handling the input can
be easily done with help of Intuition's IDCMP system. IDCMP stands for
Intuition's Direct Communications Message Ports system. Hard name but very easy
to use.
The IDCMP system is also explained, in more detail, in chapter 8 IDCMP.
If you want to use the IDCMP system you only need to follow these steps:
1. Decide what events your gadget should report. You do it by setting the
appropriate flags in the Activation field in the Gadget structure:
GADGIMMEDIATE Set this flag if you want your program to receive a message
immediately when the user selects this gadget.
RELVERIFY Set this flag if you want your program to receive a message when
the user releases (while still pointing at it) this gadget. If the user
releases the gadget after having moved the pointer away from the select box,
your program will not receive any message.
FOLLOWMOUSE Set this flag if you want your program to receive a message
every time the mouse is moved while this gadget is selected.
2. If the gadgets are connected to a window you need to tell Intuition which
messages should be sent to your program. You do it by setting the appropriate
flags in the IDCMPFlags field in the NewWindow structure:
GADGETDOWN If a gadget connected to a window has the GADGIMMEDIATE flag
set, you should set the GADGETDOWN flag.
GADGETUP If a gadget connected to a window has the RELVERIFY flag set,
you should set the GADGETUP flag.
MOUSEMOVE If a gadget connected to a window has the FOLLOWMOUSE flag set,
you should set the MOUSEMOVE flag.
CLOSEWINDOW If you have connected the Close window gadget (System gadget) to
your window, you can set this bit, and your program will receive a message when
the user selects this gadget. Remember, Intuition does not close the window
automatically when the user clicks on the Close window gadget. It is up to your
program to decide what to do when you receive a CLOSEWINDOW event. (See
Example1)
3. Once your program is running it is time to try to collect and examine the
messages sent to us by Intuition. One very commonly used way of doing it is to
put the program to sleep [ Wait() ] and it will wake first when a message has
arrived. We will then try to collect it [ GetMsg() ], and then (if success)
examine the message. When we are finished with it we send it back [ ReplyMsg()
] so Intuition can send us another message if there is one. We can then put the
program to sleep again, and so on.
When we collect a message with help of the function GetMsg() we actually
receive a pointer to an IntuiMessage structure or NULL if there was nothing for
us. The IntuiMessage structure looks like this:
struct IntuiMessage
{
struct Message ExecMessage;
ULONG Class;
USHORT Code;
USHORT Qualifier;
APTR IAddress;
SHORT MouseX, MouseY;
ULONG Seconds, Micros;
struct Window *IDCMPWindow;
struct IntuiMessage *SpecialLink;
};
This structure is fully explained in chapter 8 IDCMP, so you do not need to
bother so much about it for the moment. However, there are two variables in the
structure that we need to understand. They are:
Class:
When a message is sent this field contains the reason why it was sent. It
contains an IDCMP flag which tells us what has happened. For example, if the
user has selected a gadget with the GADGIMMEDIATE flag set, this variable is
equal to GADGETDOWN.
IAddress:
This is a pointer to the gadget (or similar) which sent the message. For
example, if a program receives a message telling us that a gadget was selected,
we need to know which gadget since there may be several gadget connected to the
same window. This pointer points to that gadget.
Here is an example of a program which collects IDCMP messages:
main()
{
/* Declare a variable in which we will store the IDCMP */
/* flag: */
ULONG class;
/* Declare a pointer in which we will store the address */
/* of the object (gadget) which sent the message: */
APTR address;
/* Declare a pointer to an IntuiMessage structure: */
struct IntuiMessage *my_message;
/* ... */
/* (This is an endless loop) */
while( TRUE )
{
/* 1. Put our program to sleep, and wake up first when */
/* we have received a message. Do not bother for the */
/* moment about all these funny thing we put inside */
/* the Wait () function. I will talk about that later */
/* on. */
/* Wait until we have received a message: */
Wait( 1 << my_window->UserPort->mp_SigBit );
/* 2. We have now received a message and we shall now */
/* try to collect it. If success the function GetMsg() */
/* will return a pointer to an IntuiMessage */
/* structure, otherwise it will return NULL. */
/* Collect the message: */
my_message = GetMsg( my_window->UserPort );
/* 3. If we have collected a message successfully we save */
/* some important values which we later can use. */
if( my_message )
{
/* Save the code variable: */
class = my_message->Class;
/* Save the address of the gadget: */
address = my_message->IAddress;
/* 4. After we have saved all important values we */
/* reply as fast as possible. Once we have replied */
/* we can NOT use the IntuiMessage structure any */
/* more! */
ReplyMsg( my_message );
/* 5. We can now check what message was sent to us. */
/* Check which IDCMP flag was sent: */
switch( class )
{
case GADGETDOWN: /* The user has selected a gadget: */
/* If we want to check which gadget sent the */
/* message we simply need to check the */
/* address pointer: */
if( address == &my_first_gadget)
/* The gadget "my_first_gadget" selected. */
/* Do what ever you want... */
if( address == &my_second_gadget)
/* The gadget "my_second_gadget" selected. */
/* Do what ever you want... */
break;
case GADGETUP: /* The user has released a gadget: */
/* Do what ever you want... */
break;
case MOUSEMOVE: /* The user has moved the mouse */
/* while a gadget was selected. */
/* Do what ever you want... */
break;
case CLOSEWINDOW: /* The user has selected the close */
/* window gadget. Time to quit. */
/* Do what ever you want... */
break;
}
}
}
/* ... */
}
4.9 FUNCTIONS
Here are some commonly used functions:
ActivateGadget()
This function is used to activate a string or integer gadget, although other
gadgets too can be activated (selected) with this function. This function can
be used to make it easier for the user to input text or values. Since the
function will automatically activate (select) a specified gadget can the user
continue to keep his/her fingers on the keyboard and does not have to fiddle
around with the mouse each time he/she wants to input some values.
Synopsis:
ActivateGadget( gadget, window, requester );
gadget:
(struct Gadget *) Pointer to the gadget which should be selected.
window:
(struct Window *) Pointer to the window which the gadget is connected to.
requester:
(struct Requester *) If the gadget is connected to a requester, set this
pointer to point to that requester, else NULL. Important, if this gadget is
connected to a requester, it must be displayed when you execute this command!
(See chapter 5 REQUESTERS for more information about requesters.)
ActivateWindow()
This function is used to activate a specified window.
Synopsis:
ActivateWindow( window );
window:
(struct Window *) Pointer to the window which should be activated. Note! The
window must be open when you call the function!
RefreshGadgets()
This function redraws all the gadgets in the list, starting by the specified
gadget. If you for example have added or deleted a gadget you need to call this
function to see the changes. On the other hand, if you have changed the imagery
of a gadget, or the gadget's image has been trashed by something, you can also
use this function to refresh the display.
Synopsis:
RefreshGadgets( gadget, window, requester);
gadget:
(struct Gadget *) Pointer to the gadget where the redrawing should start. This
gadget, and all the following gadgets in the list will be redrawn.
window:
(struct Window *) Pointer to the window which the gadgets are connected to.
requester:
(struct Requester *) If the gadget is connected to a requester, set this
pointer to point to that requester, else NULL. Important, if this gadget is
connected to a requester, it must be displayed when you execute this command!
(See chapter 5 REQUESTERS for more information about requesters.)
AddGadget()
This function adds a gadget to the gadget list.
Synopsis:
result = AddGadget( window, gadget, position );
result:
(long) The actual position of the gadget when it has been added.
window:
(struct Window *) Pointer to the window, to which the gadget should be added.
gadget:
(struct Gadget *) Pointer to the gadget which will be added.
position:
(long) Position in the gadget list. (Starts from zero). Eg:
0 -> Before all other gadgets.
1 -> After the first gadget, but before the second.
If a too big value is entered (or -1), the gadget will be placed last in the
list.
Important, after your program has added the necessary gadgets, you need to call
the function RefreshGadgets() in order to see your changes. You may add (or
take away) several gadgets, but when you are finished you must call that
function.
RemoveGadget()
This function removes a gadget from the list:
Synopsis:
result = RemoveGadget( window, gadget );
result:
(long) The position of the removed gadget or -1 if something went wrong.
window:
(struct Window *) Pointer to the window that the gadget is connected to.
gadget:
(struct Gadget *) Pointer to the gadget which will be removed.
Important, after your program has removed the necessary gadgets, you need to
call the function RefreshGadgets() in order to see your changes. You may take
away (or add) several gadgets, but when you are finished you must call that
function.
OnGadget()
This function enables a gadget (removes the GADGDISABLED bit in the gadget
structure's Flags field):
Synopsis:
OnGadget( gadget, window, requester );
gadget:
(struct Gadget *) Pointer to the gadget which will be enabled.
window:
(struct Window *) Pointer to the window that the gadget is attached to.
requester:
(struct Requester *) If the gadget is connected to a requester, set this
pointer to point to that requester, else NULL. Important, if this gadget is
connected to a requester, it must be displayed when you execute this command!
Remember, as long as the gadget is disabled the user can not select it, and it
will not broadcast any messages. A disabled gadget is drawn as usual except
that it "ghosted".
OffGadget()
This function disables a gadget (sets the GADGDISABLED bit in the gadget
structure's Flags field):
Synopsis:
OffGadget( gadget, window, requester );
gadget:
(struct Gadget *) Pointer to the gadget which will be disabled.
window:
(struct Window *) Pointer to the window that the gadget is attached to.
requester:
(struct Requester *) If the gadget is connected to a requester, set this
pointer to point to that requester, else NULL. Important, if this gadget is
connected to a requester, it must be displayed when you execute this command!
ModifyProp()
This function modifies a proportional gadget's values and knob. For example, if
your program is reading files from the disk, VertBody was maybe equal to 0xFFFF
(MAXBODY) in the beginning, but as more files are collected from the disk, you
maybe want to change the size of the knob etc. You then simply call this
function and it will change the values as well as redraw the gadget.
Synopsis:
ModifyProp( gadget, window, requester, flags, horiz_pot, vert_pot, horiz_body,
vert_body );
gadget:
(struct Gadget *) Pointer to the proportional gadget which should be changed
and redrawn.
window:
(struct Window *) Pointer to the window which the proportional gadget is
connected to.
requester:
(struct Requester *) If the gadget is connected to a requester, set this
pointer to point to that requester, else NULL. Important, if this gadget is
connected to a requester, it must be displayed when you execute this command!
flags:
(long) Here is the list of all flags you may use:
FREEHORIZ Set this bit if you want the user to be able to move the knob
horizontally.
FREEVERT Set this bit if you want the user to be able to move the knob
vertically.
AUTOKNOB Set this bit if you want that the size of the knob to be
controlled by Intuition. (HorizBody and VertBody affects the size of the
Autoknob.)
- If you want to use Intuition's Autoknob you should give GadgetRender a
pointer to an Image structure. (You do not need to initialize the Image
structure since Intuition takes care of it.)
- If you on the other hand would like to use your own knob image, you give
GadgetRender a pointer to your Image structure, which you have initialized
yourself.
PROPBORDERLESS Set this bit if you do not want any border around the container.
(See chapter 4.7 for more information.)
horiz_pot:
(long) This variable contains the actual (horizontally) proportional value. If
the knob should be moved 25% to the right, HorizPot should be set to 25% of
MAXPOT (0xFFFF). (0xFFFF * 0.25 = 0x3FFF)
vert_pot:
(long) Same as HorizPot except that this is the vertically proportional value.
horiz_body:
(long) Describes how much HorizPot should change every time the user clicks
inside the container. If the volume of a melody can be between 0-63 (64 steps),
HorizPot should change 1/64 each time. The HorizBody should therefore be set
to:
1/64 * MAXBODY (0xFFFF) == 3FF
HorizBody describes also how much the user can see/use of the entire data. For
example, if you have a list of 32 file names, and the user only can see 8 names
at one time (25%), the knob (AUTOKNOB) should fill 25% of the container.
HorizBody should in this case be set to: MAXBODY * 8 / 32 (25% of 0xFFFF) ==
3FFFF
vert_body:
Same as HorizBody except that it affects VertPot, and the vertical size of the
knob (AUTOKNOB).
4.10 EXAMPLES
Example 1
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. (Same as Example3 in chapter
2 WINDOWS, except that we have added an IDCMP check on the Close window
gadget.)
Example 2
Same as Example 1 except that we have added a Boolean gadget with the text
"PRESS ME".
Example 3
Same as Example 2 except that the on/off state of the gadget is toggled each
time the user hits the gadget.
Example 4
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have put
two Boolean gadgets with the text "GADGET 1" and GADGET 2".
Example 5
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have put
a Boolean gadget with two Image structures connected to it. Each time the user
clicks on the gadget it will change images, lamp on/lamp off.
Example 6
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have put
a Boolean gadget with a connecting mask. The gadget will only be highlighted
when the user selects this gadget while pointing inside the specified (masked)
area.
Example 7
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have put
a String gadget.
Example 8
Same as Example 7 except that it is an Integer gadget.
Example 9
Same as Example 7 except that it is a Proportional gadget.
Example 10
Same as Example 9 except that the Proportional gadget uses a custom image knob.
Example 11
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have put
a Proportional gadget where the knob can be moved both horizontally and
vertically.
Example 12
This program will open a SuperBitmap window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have put
two Proportional gadgets, one on the right side, and one at the bottom. With
help of these two gadgets, the user can move around the BitMap.
This example is for experienced programmers only, since it uses some functions
etc which we have not discussed yet. I have, however, included it here since it
is a good example on how you can combine Proportional gadgets with SuperBitmap
windows.
Example 13
This example demonstrates how to use six string gadgets which are automatically
activated (selected) when the user release the gadget above.
REQUESTERS
5.1 INTRODUCTION
Requesters are boxes filled with some sort of information which the user need
to respond to. It can be as simple as a question to insert a disk in the
internal drive, or a fully functional file requester. Requesters are like small
windows with some gadgets connected to it, and they will first disappear when
the user has "satisfied the request".
5.2 DIFFERENT TYPES OF REQUESTERS
There exist three different types of requesters:
- System requesters
- Application requesters
- Double-menu requesters
5.2.1 SYSTEM REQUESTERS
System requesters are opened and maintained by Intuition, and your program has
no control over them. If the user, for example, is trying to load a file from
drive df1:, and there is no disk present, the operating system would open the
following request:
-----------------------------------
| System Request ============[*][*]
-----------------------------------
| No disk present | |
| in unit 1 | |
| | |
| --------- ---------- | |
| | Retry | | Cancel | | |
| --------- ---------- | |
--------------------------------[*]
One important thing about System requesters is that they are like small
windows. You can move around them, push them behind or in front of other
windows/requesters, and resize them.
5.2.2 APPLICATION REQUESTERS
This is the type of requester your program can open. They can be of any size
(limited only by the size of the screen), and can be as simple or as
complicated as you want.
If you only want a Yes/No (True/False) requester you can call the function
AutoRequest(), and Intuition will open and take care of the rest. If you on the
other hand want a more sophisticated requester you need to declare and
initialize a Requester structure with your requirements, and call the function
Request().
It is important to notice that an Application requester can not be moved
around, resized etc (the window containing the requester can still, of course,
be moved around and resized). It is only the System requesters, and the very
simple requesters opened by the AutoRequest function, which acts like small
windows.
There is also one other big difference. When an Application requester has been
activated the user can no longer select gadgets connected to the window. The
window has been "frozen". Eg. try Example4, and you will notice that you can
not select the close-window gadget as long as the requester is active. On
the other hand, if a System requester has been activated, the user can still
click on the close-window gadget, and a CLOSEWINDOW message is sent.
5.2.3 DOUBLE-MENU REQUESTERS
Double-menu requesters are like normal Application requesters except that they
will open first, and only, when the user double-clicks on the mouse menu
button. To create a Double-menu requester you need to declare and initialize a
Requester structure, and then call the function SetDMRequest(). Whenever the
user from now on double-clicks on the menu button on the mouse, the requester
will be opened. Call the function ClearDMRequest() when you do not want the
user to be able to open the requester any more.
Only one DM-requester may be connected to each window.
5.3 GRAPHICS FOR REQUESTERS
You can render a requester in two different ways. You can either tell Intuition
what you want, and everything is rendered for you, or you can supply Intuition
with your own customized Bitmap (which has been rendered by yourself).
If you want Intuition to draw the requester for you, you only need to decide
what colour the background of the requester should be filled with, and declare
and initialize one or more Border and IntuiText structures.
If you supply your own customized Bitmap Intuition will not draw anything
itself. That means that all gadget connected to that requester does not need to
have any Border/IntuiText/Image structures connected to them, since Intuition
will not bother about them.
5.4 POSITION
The requester can either be positioned relative to the top left corner of the
window, or relative to the pointer position. If you want to position the
requester relative to the window, you simply set the LeftEdge and TopEdge
variables as desired. If you, on the other hand, want it relative to the
pointer position, set the POINTREL flag, and initialize RelLeft and RelTop as
desired.
5.5 REQUESTERS AND GADGETS
When you create a requester, except when you call the function AutoRequest(),
you need to connect at least one gadget to the requester. Gadgets connected to
a requester works exactly the same as gadgets connected to a window but with
two important differences:
1. Every gadget connected to a requester MUST have the REQGADGET flag set in
the GadgetType field.
2. At least one gadget must satisfy the request, which means at least one
gadget must have the ENDGADGET flag set in the Activation field. (Once a gadget
with an ENDGADGET flag set is selected, the requester is satisfied, and will
close.)
Remember that the user should always be able to find a safe way to leave the
requester without affecting anything. The "way out gadget" (CANCEL, RESUME etc)
should also always be placed on the right side in the requester. Here is an
example:
---------------------------------------
| System Request ================[*][*]
---------------------------------------
| Do you really want to quit? | |
| | |
| | |
| ------- ------ | |
| | Yes | | No | | |
| ------- ------ | |
------------------------------------[*]
Note that the Yes/True/Retry button is always on the left side and that the
No/False/Cancel button is always on the right side.
IMPORTANT! Make sure that the Gadgets are inside the requester, since Intuition
will not do any boundary checking.
5.6 SIMPLE REQUESTERS
If you just want a simple requester with a True/False (or just False) option,
you can use the function AutoRequest(). You give Intuition some information
about how the requester should look like (height, text etc), and Intuition
takes care of everything else. It opens the requester, put your program to
rest, and
when finished, returns a boolean value which tells your program what the user
selected. If the user selected the left gadget (positive) it returns TRUE, and
if the user selected the right gadget (negative) it returns FALSE.
Example:
result = AutoRequest( window, info_text, pos_text, neg_text, pos_IDCMP,
neg_IDCMP, width, height );
window:
Pointer to a window if there exist one, else NULL.
info_text:
Pointer to an IntuiText structure containing the "body text".
pos_text:
Pointer to an IntuiText structure containing the "positive text". Eg: "TRUE",
"YES", "RETRY" etc. (Optional)
neg_text:
Pointer to an IntuiText structure containing the "negative text". Eg: "FALSE",
"NO", "CANCEL" etc.
pos_IDCMP:
The IDCMP flags which satisfy the "positive" gadget. (The flag RELVERIFY is
already set.)
pos_IDCMP:
The IDCMP flags which satisfy the "negative" gadget. (The flag RELVERIFY is
already set.)
width:
How many pixels wide the requester should be.
height:
How many lines high the requester should be.
5.7 OPEN A REQUESTER
If you want to use a more complicated requester instead of the Simple requester
you need to:
1. Declare and initialize a Requester structure with your requirements.
2. Declare and initialize the Gadget structures which are going to be connected
to the requester.
3. Call the function Request() in order to display the requester as a normal
requester, or call the function SetDMRequest() to enable the user to bring up
the requester as a Double-menu requester.
5.7.1 INITIALIZE A REQUESTER
If you want to use a requester you need to declare and initialize a Requester
structure which look like this:
struct Requester
{
struct Requester *OlderRequest;
SHORT LeftEdge, TopEdge;
SHORT Width, Height;
SHORT RelLeft, RelTop;
struct Gadget *ReqGadget;
struct Border *ReqBorder;
struct IntuiText *ReqText;
USHORT Flags;
UBYTE BackFill;
struct Layer *ReqLayer;
UBYTE ReqPad1[32];
struct BitMap *ImageBMap;
struct Window *RWindow;
UBYTE ReqPad2[36];
};
OlderRequest:
Initialized and maintained by Intuition. Set to NULL.
LeftEdge, TopEdge:
Position of the requester relative to the top left corner of the window (if the
POINTREL flag is not set).
Width, Height:
Size of the requester.
RelLeft, RelTop:
If the POINTREL flag is set, these values describes the position of the
requester relative to the pointer.
ReqGadget:
Pointer to the first gadget in the linked list. Remember, there must exist at
least one gadget connected to the requester with the ENDGADGET flag set.
ReqBorder:
Pointer to a Border structure used to render the requester.
ReqText:
Pointer to an IntuiText structure used to print text in the requester.
Flags:
There exist two flags which you may set:
POINTREL: Set this flag if you want to position the requester relative to the
pointer. Set the RelLeft, RelTop as desired.
PREDRAWN: If you supply with your own customized Bitmap set this flag, and
Intuition will not try to draw anything itself.
Intuition sets these flags:
REQACTIVE: This flag is set when the requester is activated, and cleared
when the requester is closed (deactivated).
REQOFFWINDOW: This flag is set if the requester is active and positioned
outside the window. (The user has maybe shrinked the window so it is smaller
than you thought.)
SYSREQUEST: This flag is set if the requester is of the type System
requester.
BackFill:
Colour register used to fill the requester with before any drawing takes place.
For example, if you want to render the graphics on an orange background, you
set the BackFill field to 3 (orange, normal WB colours).
ReqLayer:
Pointer to the Layer structure for this requester. Initialized and maintained
by Intuition. Set to NULL.
ReqPad1:
Initialized and maintained by Intuition. Set to NULL. (Used by the system.)
ImageBMap:
If the bit PREDRAWN is set, this field should contain a pointer to a customized
Bitmap, else NULL.
RWindow:
Initialized and maintained by Intuition. Set to NULL. (Used by the system,
points back to the Window which this requester is connected to.)
ReqPad2:
Initialized and maintained by Intuition. Set to NULL. (Used by the system.)
Here is an example of how to initialize a Requester structure:
struct Requester my_requester=
{
NULL, /* OlderRequester, used by Intuition. */
40, 20, /* LeftEdge, TopEdge, 40 pixels out, 20 */
/* lines down. */
320, 100, /* Width, Height, 320 pixels wide, 100 */
/* lines high. */
0, 0, /* RelLeft, RelTop, Since POINTREL flag */
/* is not set, Intuition ignores these */
/* values. */
&my_first_gadget, /* ReqGadget, pointer to the first */
/* gadget. */
&my_border, /* ReqBorder, pointer to a Border */
/* structure. */
&my_text, /* ReqText, pointer to a IntuiText */
/* structure. */
NULL, /* Flags, no flags set. */
3, /* BackFill, draw everything on an */
/* orange background. */
NULL, /* ReqLayer, used by Intuition. Set to */
/* NULL. */
NULL, /* ReqPad1, used by Intuition. Set to */
/* NULL. */
NULL, /* ImageBMap, no predrawn Bitmap. Set */
/* to NULL. (The PREDRAWN flag was not */
/* set.) */
NULL, /* RWindow, used by Intuition. Set to */
/* NULL. */
NULL /* ReqPad2, used by Intuition. Set to */
/* NULL. */
};
If you would like to supply your own customized and predrawn Bitmap, instead of
letting Intuition render the requester you need to:
1. Set the flag PREDRAWN in the Flags field.
2. Set the ImageBMap to point at your BitMap structure.
Remember that Intuition will now not draw anything for you. The ReqBorder,
ReqText and BackFill variables are ignored, and should therefore be set to
NULL. Intuition will also not render the gadgets connected to the requester.
Because of this it is important that the rendering of the Bitmap is done
carefully, and that the graphics correspond to where the gadgets are etc.
5.7.2 HOW TO ACTIVATE AN APPLICATION REQUESTER
If you have declared and initialized a Requester structure you only need to
call the function Request() in order to activate it.
Example:
result = Request( my_requester, my_window );
my_requester:
Pointer to the Requester structure.
my_window:
Pointer to the Window structure which the requester should be connected to.
result:
Boolean value returned. If Intuition could successfully open the requester the
function returns TRUE, else (something went wrong, not enough memory etc) the
function returns FALSE.
If you on the other hand would like the requester to be a Double-menu requester
you should call the function SetDMRequest(), which will allow the user to
activate the requester by double clicking the mouse menu button.
Example:
result = SetDMRequest( my_window, my_requester );
my_window:
Pointer to the Window structure which the requester should be connected to.
my_requester: Pointer to the Requester structure.
result:
Boolean value returned. If Intuition could successfully open the requester the
function returns TRUE, else (some thing went wrong, not enough memory or the a
DM requester is already connected to the window etc) the function returns
FALSE.
You can after you have called the SetDMRequest() function successfully, take
away the ability for the user to open the requester by calling the function
ClearDMRequest().
Example:
result = ClearDMRequest( my_window );
my_window:
Pointer to the Window structure which the requester is connected to.
result:
If the function could disable the user to activate the DM-requester it returns
TRUE, else (something went wrong, the requester is in use etc) it returns
FALSE.
5.8 IDCMP FLAGS
There exist three IDCMP flags which are special for the requesters. When a
requester is activated you can, if you want to, receive a message telling you
that a requester was activated. This is especially useful if you are using
Double-menu requesters, since this is the only way to check if the requester
was opened.
If you want to get a message every time a requester is activated, you need to
set the flag REQSET in the IDCMPFlags field in the NewWindow structure. Set the
flag REQCLEAR if you want to receive a message every time a requester is
deactivated. See Example5 for more details.
There exist also one special IDCMP flag called REQVERIFY. If you set this flag
in the IDCMPFlags field in the NewWindow structure your program will receive a
message when the user is trying to activate a Double-menu requester. The
interesting thing about this flag is that the requester will not be opened
until your program has replied, ReplyMsg(). Your program can therefore finish
of something (like finish of with drawing something etc) before the requester
is displayed, and when your program is ready, it can reply, and the requester
is activated. See Example6 for more information.
5.9 FUNCTIONS
Here are some commonly used functions:
AutoRequest()
This function opens a Simple requester. Intuition will automatically activate
it and take care of the response from the user. It will return TRUE if the left
gadget was selected, and FALSE if the right gadget was selected.
Synopsis:
result = AutoRequest( my_window, info_txt, pos_txt, neg_txt, pos_IDCMP,
neg_IDCMP, width, height );
my_window:
(struct Window *) Pointer to a window if there exist one, else NULL.
info_txt:
(struct IntuiText *) Pointer to an IntuiText structure containing the "body
text".
pos_txt:
(struct IntuiText *) Pointer to an IntuiText structure containing the "positive
text". Eg: "TRUE", "YES", "RETRY" etc. (Optional)
neg_txt:
(struct IntuiText *) Pointer to an IntuiText structure containing the "negative
text". Eg: "FALSE", "NO", "CANCEL" etc.
pos_IDCMP:
(long) IDCMP flags which satisfy the "positive" gadget. (The flag RELVERIFY is
already set.)
pos_IDCMP:
(long) IDCMP flags which satisfy the "negative" gadget. (The flag RELVERIFY is
already set.)
width:
(long) How many pixels wide the requester should be.
height:
(long) How many lines high the requester should be.
result:
(long) Boolean value. The function returns TRUE if the positive gadget was
satisfied, and FALSE if the negative gadget was satisfied.
Request()
This function activates a requester connected to a window.
Synopsis:
result = Request( my_requester, my_window );
my_requester:
(struct Requester *) Pointer to the Requester structure.
my_window:
(struct Window *) Pointer to the Window structure which the requester should be
connected to.
result:
(long) Boolean value returned. If Intuition could successfully open the
requester the function returns TRUE, else (something went wrong, not enough
memory etc) the function returns FALSE.
EndRequest()
This function deactivates a requester which has been activated.
Synopsis:
EndRequest( my_requester, my_window );
my_requester:
(struct Requester *) Pointer to the Requester structure which will be removed.
my_window:
(struct Window *) Pointer to the Window structure which the requester is
connected to.
SetDMRequest()
This function allows the user to activate a Double-menu requester by clicking
twice on the mouse menu button.
Synopsis:
result = SetDMRequest( window, requester );
window:
(struct Window *) Pointer to the Window structure which the requester should be
connected to.
requester:
(struct Requester *) Pointer to the Requester structure.
result:
(long) Boolean value returned. If Intuition could successfully open the
requester the function returns TRUE, else (something went wrong, not enough
memory or a DM requester is already connected to the window, etc) the function
returns FALSE.
ClearDMRequest()
This function disables a Double-menu requester. The user can not open the
requester any more.
Synopsis:
result = ClearDMRequest( my_window );
my_window:
(struct Window *) Pointer to the Window structure which the requester is
connected to. The DMRequest pointer in the Window structure is set to NULL.
result:
(long) If the function could disable the DM-requester it returns TRUE, else
(something went wrong, the requester is in use etc) it returns FALSE.
5.10 EXAMPLES
Example 1
This example opens a Simple requester by calling the function AutoRequest. It
displays a message "This is a very simple requester!", and has only one gadget
connected to it (on the right side of the requester) with the text "OK".
Example 2
Same as Example 1, except that the requester displays a message "Do you really
want to quit?", and allows the user to choose between "Yes" and "No". The
program will continue to reopen the requester until the user has chosen "Yes".
Example 3
Same as Example 1, except that this requester displays a message "Insert a disk
in any drive!", and allows the user to choose between "Yes" and "No". The
program will continue to reopen the requester until the user has chosen "Yes"
or inserted a disk.
Example 4
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have
activated an Application requester with a connecting gadget. The requester will
first be satisfied when the user has selected the gadget, and will then be
deactivated. The window can now be closed.
Example 5
Same as Example 4, except that the requester is first activated when the user
double-clicks on the right mouse button. This example shows how to create a
Double-menu requester, and how to monitor the IDCMP flags REQSET and REQCLEAR.
Example 6
Same as Example 5, except that whenever the user double-clicks on the right
mouse button, we will receive a REQVERIFY message, and first when we have
replied, will the requester be activated. This example shows how to use the
REQVERIFY flag.
Example 7
This program will open a normal window which is connected to the Workbench
Screen. The window will use all System Gadgets, and will close first when the
user has selected the System gadget Close window. Inside the window we have
activated an Application requester with three connecting gadgets. Two are
Boolean gadgets ("OK and "CANCEL"), and one is a String gadget.
Example 8
Same as Example 7, except that it is an Integer gadget.
Example 9
Same as Example 8, except that it is a Proportional gadget.
Example 10
This example demonstrates how you use a requester with a predrawn bitmap. This
is very useful when you want colourful and catching requesters. The advantage
with a special bitmap is that if the window which the requester is tied to is
resized, the drawing will not be destroied.
The graphics data is stored in a separate file called "Example10Graphics.c".
Both this and the graphical file should be compiled separately, then linked
together. If you have a SAS (Lattice) C Compiler you would do like this:
lc Example10.c
lc Example10
Graphics.c
blink with Example10.lnk
This program will NOT try to erase the disk! It is ony a demonstration how to
use a requester.
ALERTS
6.1 INTRODUCTION
Alerts is the last resource your program can use in order to inform the user
about a problem. When your program displays an alert all screens are moved
down, and a black and red box is opened at the top of the display. It not only
gives the user a hart attack, but it will also tell him/her what went wrong,
and if there is a way out.
6.2 DIFFERENT LEVELS OF WARNINGS
There exist three levels of warnings:
1. If you want to alert the user that something went wrong, but it is nothing
serious, you can flash the screens. You do it by calling the function
DisplayBeep(), and the background colour of all screens will be flashed.
2. If something went wrong, and you want to inform the user, maybe even want
that he/she does something, you should open a Requester. (Described in chapter
5 REQUESTERS.)
3. If something went TERRIBLE WRONG, (the system is crashing etc) your program
should activate an Alert message, DisplayAlert().
6.3 HOW TO USE THE DISPLAYALERT() FUNCTION
Synopsis:
result = DisplayAlert( nr, message, height );
nr:
(long) Value which describes if it is a RECOVERY_ALERT or a DEADEND_ALERT.
message:
(char *) Pointer to an array of characters (char). It contains the strings we
want to display, and some extra information (position etc). The string itself
is divided into substrings, which all contain information about its position
etc.
Each substring consists of:
- 2 bytes (16-bit) which are used for the x position of the text.
- 1 byte (8-bit) which is used for the y position of the text.
- The text string which ends with a NULL ('\0') sign.
- A Continuation byte. If it is TRUE there is another substring after this one,
else this was the last substring.
(See below for more information)
height:
(long) The height of the Alert box.
result:
(long) The function DisplayAlert() returns a boolean value. If it is a
RECOVERY_ALERT and the user pressed the left mouse button it returns TRUE else,
if the user pressed the right mouse button, it returns FALSE. If it is a
DEADEND_ALERT the function will immediate return FALSE.
6.4 EXAMPLES OF STRINGS AND SUBSTRINGS
If we want to display the following Alert message:
---------------------------------------------------------------
| |
| ERROR! Not enough memory! |
| |
---------------------------------------------------------------
the string would be declared and initialized like this:
/* Declare the array of char (the string): */
char message[30]; /* 30 bytes needed. */
/* Fill the string with the message: (Remember to give */
/* space for the first 3 bytes which will contain the x/y */
/* position.) */
strcpy( message, " ERROR! Not enough memory!" );
/* The NULL sign is automatically placed at position 28. */
/* Fill the string with the position (x,y) (first 3 bytes) */
message[0]=0; /* X position is less than 256, therefore 0. */
message[1]=32; /* 32 pixels out. */
message[2]=16; /* 16 lines down. */
/* Set the Continuation byte to FALSE since there are no */
/* more substrings after this one: */
message[29]=FALSE;
If we on the other hand want to display the following Alert message:
---------------------------------------------------------------
| |
| ERROR! Not enough memory! |
| |
| Buy a memory expansion! |
| |
---------------------------------------------------------------
the string would be declared and initialized like this:
/* Declare the array of char (the string): */
char message[58]; /* 58 bytes needed. */
/* Fill the array with the first substring: (Remember to */
/* give space for the first 3 bytes which will contain */
/* the x/y position.) */
strcpy( message, " ERROR! Not enough memory!" );
/* Add the second substring: (Remember this time to give */
/* space for 5 bytes in the beginning of the string. */
/* They are used for the NULL sign which finish off the */
/* first substring, the Continuation byte, and three */
/* bytes for the position for the second substring.) */
strcat( message, " Buy a memory expansion!");
/* The NULL sign which finish of the second substring is */
/* automatically placed at position 56. */
/* Fill the first substring with the position (x,y) */
/* (first 3 bytes) */
message[0]=0; /* X position is less than 256, therefore 0. */
message[1]=32; /* 32 pixels out. */
message[2]=16; /* 16 lines down. */
/* Add the NULL sign which finish of the first substring: */
/* (It was deleted when we connected the two strings with */
/* the strcat() function.) */
message[28]='\0';
/* Set the Continuation byte to TRUE which tells */
/* Intuition that there is another substring coming: */
message[29]=TRUE;
/* Fill the second substring with the position (x,y): */
message[30]=0; /* X position is less than 256. */
message[31]=32; /* 32 pixels out. */
message[32]=32; /* 32 lines down. */
/* Set the Continuation byte to FALSE since there are */
/* no more substrings after this one: */
message[57]=FALSE;
6.5 FUNCTIONS
DisplayAlert()
This function activates an Alert message.
Synopsis:
result = DisplayAlert( nr, message, height );
nr:
(long) Value which describes if it is a RECOVERY_ALERT or a DEADEND_ALERT.
message:
(char *) Pointer to an array of characters (char). It contains the strings we
want to display, and some extra information (position etc). The string itself
is divided into substrings, which all contain information about its position
etc.
- 2 bytes (16-bit) which are used for the x position of the text.
- 1 byte (8-bit) which is used for the y position of the text.
- The text string which ends with a NULL ('\0') sign.
- A Continuation byte. If it is TRUE there is another substring after this one,
else this was the last substring.
height:
(long) The height of the Alert box.
result:
(long) The function DisplayAlert() returns a boolean value. If it is a
RECOVERY_ALERT and the user pressed the left mouse button it returns TRUE else,
if the user pressed the right mouse button, it returns FALSE. If it is a
DEADEND_ALERT the function will immediate return FALSE.
6.6 EXAMPLES
Example 1
This example displays an Alert message at the top of the display.
MENUS
7.1 INTRODUCTION
If you have been working on the Amiga you have probably used menus a lot. They
are flexible tools which are easy to access and are not complicated to set up.
In this chapter we will look at how you can create your own menus, how to use
all the special features offered by Intuition, and how the communication
between the user and the menus is executed.
7.2 MENU DESIGN
You can connect a "menu strip" to every window, and when the user presses down
the right mouse button, the active window's menu strip is shown at the top of
the display.
An example of a "menu strip":
Project Block Windows Search
The user can now move the pointer to one of the menu headings, while still
holding the right mouse button pressed, and that menu's "item box" is
displayed.
An example of a "item box":
PROJECT Block Windows Search
|----------|
| Open |
| Save |
| Save as |
| Print |
| Info |
| Quit |
|----------|
The user can now choose the "menu item" he/she wants. The user does it by
moving the pointer to the desired menu item, and releases the right mouse
button. If the user wants he/she can pick several menu items at the same "menu
action" by holding down the right mouse button as normal, but click with the
left mouse button on each menu item the user wants to select. The user can also
"drag" (holding both mouse buttons down) over several menu items if he/she
wants to select all of them.
You can connect a separate menu to an item if you want. That menu is usually
referred as "submenu", and it consists of one or more "subitems".
An Example of "subitems": (Note that the subitem box overlap the item box!)
Project Block Windows Search
|----------|
| Open |
| Save |
| Save a--------------
| PRINT | to printer |
| Info | to a file |
| Quit --------------
|----------|
7.3 HOW TO ACCESS MENUS FROM THE KEYBOARD
If you want you can allow the user to select certain menu items from the
keyboard. This is very handy if it is a command the user will often use, and
you want to provide him/her with a shortcut. The user can access the menu item
by pressing the right "Amiga key" + another key. For example, if the user
should
be able to access the menu item "Open" from the keyboard by pressing the "Amiga
key" + "O", Intuition will automatically add the sign "[A] O" after the item's
name:
PROJECT Block Windows Search
|------------|
| Open [A] O |
| Save |
| Save as |
| Print |
| Info |
| Quit |
|------------|
Your program will not notice any difference between a normal menu access, and a
shortcut.
Remember to give enough space on the right side of the item box, so the Amiga
character + sign will fit. If the item box was before 100 pixels wide you can
set the width to 100 + COMMWIDTH, and everything will fit in nicely. (COMMWIDTH
is a constant declared in the intuition.h file.) If the window is connected to
a low-resolution screen, use the constant LOWCOMMWIDTH instead.
7.4 MENU ITEMS
There exist two different types of menu items:
- Action items
- Attribute items
Action items can be selected over and over again, and every time they are
selected they will send your program a message.
Attribute items on the other hand can only be selected once, and once they have
been selected they need to be deselected before they can be selected again. The
only way to deselect an Attribute item is to mutual exclude them (explained
later in this chapter).
When an attribute item is selected Intuition will put a small checkmark, [v],
before the item's name. If you want to use your own designed checkmark instead
of the default one, you set the CheckMark pointer in your NewWindow structure
to point to an Image structure which you have declared and initialized as
desired.
If you use any attribute item in your menu you need to leave enough space at
the left side of the box for the checkmark. If you use the default checkmark
you can move the text in the menu CHECKWIDTH amount of pixels to the right.
(CHECKWIDTH is a constant declared in the intuition.h file.) If the window is
connected to a low-resolution screen (320 pixels wide), you should use the
constant LOWCHECKWIDTH instead of CHECKWIDTH.
7.5 MUTUAL EXCLUDE
This special and very useful function applies only on attribute items. The idea
with mutual exclude is that when the user selects a certain item, some other
attribute items are deselected automatically. For example, you are writing a
wordprocessor and the user should be able to print the text as normal (plain)
or with some special style (Bold, Underline or Italic). The user would then
only be allowed to select Plain or one or more of the other styles (Bold and
underlined for example). If the user selects Plain, all other styles should be
deselected (mutual excluded). If the user on the other hand selects Bold,
Underline or Italic the Plain item should be deselected.
Mutual exclude works like this:
1. If the flag CHECKIT (see the MenuItem structure) is not set, the item is not
an attribute item, it is an action item, and mutual exclude will have no effect
on this item.
2. If the flag CHECKIT is set, the item is an attribute item, and Intuition
will make sure that the CHECKED flag is not set. If it is, Intuition will
automatically remove it, and the item is unselected.
Every item has a MutualExclude field in which you can specify which items
should be deselected when this item is activated. The first bit in the field
refers to the first item in the item list, the second bit to the second item
and so on.
In our previous example we would set the Plain item's MutualExclude field to
0xFFFFFFFE (0xFFFFFFFE is equal to 11111111111111111111111111111110). This
would mutual exclude
all items except the first one. (Plain is the first item in the list, and
should of course not be mutual excluded.)
The other items (Bold, Underline and Italic) should have their field set to
0x00000001 (0x00000001 is equal to 00000000000000000000000000000001). This
would only mutual exclude the first item (the Plain item).
7.6 OPEN A MENU
If you want to attach a menu strip to a window you need to:
1. Declare and initialize one or more Menu structures. The Menu structures
should be linked together, and each Menu structure has its own list of items.
Each Menu structure represent one "menu heading"
2. Declare and initialize one or more MenuItem structures which are connected
to the Menu structures. Each MenuItem structure represent one item. You can
connect a list of "subitems" to an Item structure if you want. (Subitems use
the same data structure as normal items.)
3. Call the function SetMenuStrip(). Important, before you close the window, or
change the "menu strip" you must disconnect the menu from the window. You do it
by calling the function ClearMenuStrip().
7.6.1 INITIALIZE A MENU STRUCTURE
The Menu structure look like this:
struct Menu
{
struct Menu *NextMenu;
SHORT LeftEdge, TopEdge, Width, Height;
USHORT Flags;
BYTE *MenuName;
struct MenuItem *FirstItem;
SHORT JazzX, JazzY, BeatX, BeatY;
};
NextMenu:
Pointer to the next Menu structure in the menu strip list. The last Menu
structure in the list must have the NextMenu set to NULL.
LeftEdge:
X position of the menu.
TopEdge:
Y position of the menu. For the moment this field is unused since all menus are
positioned at the top of the display. Set it to 0.
Width:
The width of the menu.
Height:
The height of the menu. For the moment this field is unused since all menus are
as high as the height of the title bar of the screen. Set it to 0.
Flags:
There exist only two different flags for the moment:
MENUENABLED: If this flag is set the menu is enabled, and the user can select
items from it. If it is not set, the menu is ghosted and the user can not
select any items from it.
If you want the menu to be enabled when you submit it to Intuition you should
set this flag. You can later change the status by calling the functions
OnMenu() and OffMenu().
MIDRAWN: This flag is set by Intuition when this menu is displayed to the
user.
MenuName:
Pointer to a NULL-terminated string. The text will appear in the menu box at
the top of the screen.
FirstItem:
Pointer to the first MenuItem in the item list.
These funny-named variables are for internal use only:
JazzX, JazzY, BeatX, BeatY: Used by Intuition. Set to 0.
Here is an example of how to declare and initialize a Menu structure:
struct Menu my_menu=
{
NULL, /* NextMenu, no other menu structures */
/* connected. */
0, /* LeftEdge, 0 pixels to the right. */
0, /* TopEdge, for the moment ignored by */
/* Intuition. Set to 0. */
60, /* Width, 60 pixels wide. */
0, /* Height, for the moment ignored by */
/* Intuition. Set to 0. */
MENUENABLED, /* Flags, this menu should be enabled. */
"Project", /* MenuName, the title of the menu. */
&first_item, /* FirstItem, pointer to the first item */
/* in the list. */
0, 0, 0, 0 /* JazzX, JazzY, BeatX, BeatY */
};
7.6.2 INITIALIZE A MENUITEM STRUCTURE
The MenuItem structure look like this:
struct MenuItem
{
struct MenuItem *NextItem;
SHORT LeftEdge, TopEdge, Width, Height;
USHORT Flags;
LONG MutualExclude;
APTR ItemFill;
APTR SelectFill;
BYTE Command;
struct MenuItem *SubItem;
USHORT NextSelect;
};
NextItem:
Pointer to the next MenuItem structure in the item list. The last item should
have its NextItem field set to NULL.
LeftEdge:
X position of the item's select box relative to the LeftEdge of the Menu
structure.
TopEdge:
Y position of the item's select box relative to the topmost position allowed by
intuition. The topmost position is automatically calculated by Intuition which
examines the font size, how many items above etc. Set TopEdge to 0 in order to
select the topmost position.
Width:
The width of the item's select box.
Height:
The height of the item's select box.
Flags:
Here are the flags you and Intuition can use:
CHECKIT: Set this flag if you want the item to be an attribute item, else
it will be an action item. If you set this flag Intuition will put the small
checkmark in front of the itmetext when this item is selected, so make sure
there is enough space for it.
CHECKED: If the item is an attribute item (the CHECKIT flag is set), this
flag is set by Intuition when the item is selected by the user. The flag is
also automatically removed by Intuition when this item is mutual excluded.
You can set this flag yourself before you submit the menu strip to Intuition,
if you want the item to be initially selected.
HIGHITEM: The item will be highlighted, and this flag set, when the user
moves the pointer over the item's select box.
You need to set one of the following four flags which will tell Intuition what
kind of highlighting you want:
HIGHCOMP: Complement the colours of all the pixels in the item's select box.
HIGHBOX: Draw a box around the item's select box.
HIGHIMAGE: Display an alternative Image or Text.
HIGHNONE: No highlighting.
ITEMENABLED: If this flag is set the item is enabled, and the user can select
it. If this flag is not set, the item is ghosted and the user can not select
it.
If you want the item to be enabled when you submit it to Intuition you should
set this flag. You can later change the status by calling the functions
OnMenu() and OffMenu().
ITEMTEXT: If the item is rendered with text you should set this flag.
Intuition will then expect ItemFill and SelectFill to point to IntuiText
structures. If this flag is not set the item will be rendered with an image,
and Intuition will expect ItemFill and SelectFill to point to Image structures.
COMMSEQ: If the item also should be accessible from the keyboard you need
to set this flag. Remember to tell Intuition which key should be pressed
together with the "Amiga key" in order to select the item. You do it by giving
the variable Command the desired character.
ISDRAWN: This flag is set by Intuition when this item's subitems are
displayed, and cleared when not.
MutualExclude:
This variable will tell Intuition which attribute items should be mutual
excluded (deselected when this item is selected). The first bit refers to the
first item in the active list (item list or subitem list), the second bit
refers to the second item and so on. For example:
The number 0x0000000B (hexadecimal) is equal to
00000000000000000000000000001011 (binary), and Intuition would therefore try to
mutual exclude the first, the second and the fourth item.
ItemFill:
Pointer to an Image structure (the ITEMTEXT flag not set) or to an IntuiText
structure (the ITEMTEXT flag set), which will be used by Intuition to render
this item.
SelectFill:
Pointer to an Image structure (the ITEMTEXT flag not set) or to an IntuiText
structure (the ITEMTEXT flag set), which will render this item when it is
highlighted. (This field is only used if the flag HIGHIMAGE is set.)
Command:
If the user should be able to access this item from the keyboard, you need to
tell Intuition which key should be used. This field should therefore contain
the desired character. (Remember to set the flag COMMSEQ in the Flags field.)
SubItem:
Pointer to a subitem list if there exist on, else NULL. If this item is already
a subitem, this field is ignored by Intuition. (Remember, the subitem list
consists of a linked list of MenuItem structures.)
NextSelect:
This field is set by Intuition and will contain a special number if more items
after this one was selected at the same menu event, else it will contain
MENUNULL. (This will be discussed later in the chapter.) Set it to MENUNULL.
Here is an example of how to declare and initialize a MenuItem structure:
struct MenuItem my_first_item=
{
&my_second_item, /* NextItem, pointer to the next item */
/* in the list. */
0, /* LeftEdge, 0 pixels to right. */
0, /* TopEdge, the topmost position. */
150, /* Width, 150 pixels wide. */
10, /* Height, 10 lines high. */
CHECKIT| /* Flags, an attribute item. */
CHECKED| /* should initially be selected. */
COMMSEQ| /* accessible from the keyboard. */
HIGHCOMP| /* complement the colours when */
ITEMENABLED, /* highlighted. The item should */
/* be enabled. Not ghosted. */
0x00000037, /* MutualExclude, deselect if possible */
/* item: 1, 2, 3, 5 and 6. */
&my_image /* ItemFill, pointer to an Image */
/* structure used to render the item. */
/* Since the flag ITEMTEXT was not set, */
/* Intuition will assume that this is a */
/* pointer to an Image structure, and */
/* not a pointer to an IntuiText */
/* structure. */
NULL, /* SelectFill, NULL since we complement */
/* the colours instead of displaying an */
/* alternative image. */
'O', /* Command, the character which should */
/* be pressed together with the "Amiga */
/* key" in order to execute the */
/* shortcut. */
NULL, /* SubItem, this item has no subitems */
/* connected to it. */
MENUNULL /* NextSelect, set later by Intuition. */
};
7.6.3 HOW TO SUBMIT AND REMOVE A MENU STRIP TO/FROM A WINDOW
Once you have declared and initialized the necessary Menu and MenuItem
structures and linked them together you only need to call the function
SetMenuStrip(), and the menu strip is connected to your window. Remember that
you need to first open the window, before you can submit a menu strip to the
window.
If you have a pointer to an already opened window, my_window, and a pointer to
the first Menu structure in your list, my_first_menu, you attach the menu strip
like this:
SetMenuStrip( my_window, my_first_menu );
If you want to change a menu strip which is already attached to a window you
first need to remove it. You do it by calling the function ClearMenuStrip().
You can then change what ever you want to change, and attach it once again.
To remove a menu strip from a window, you only need a pointer to that window,
eg my_window, and then call the function ClearMenuStrip() like this:
ClearMenuStrip( my_window );
If a menu strip is connected to a window, and you want to close that window,
you should first remove the menu. If your program does not remove the menu
strip before it closes the window, there is a risk that the user has activated
the menu, and you would end up with a nice system crash. So, to be on the safe
side, always call the function ClearMenuStrip() before you close a window which
has a menu strip connected to it.
7.7 SPECIAL IDCMP FLAGS
There exist two special IDCMP flags which are close related to menus. They are
MENUPICK and MENUVERIFY. The IDCMP flag MENUPICK tells your program that the
user has picked zero or more items from a menu. MENUVERIFY allows your program
to finish off something before the menu is displayed, and you can even abort
the whole menu operation if you want.
7.7.1 MENUPICK
If you want your program to receive a message every time the user has picked
zero or more items/ subitems from the menu, you need to set the flag MENUPICK
in the IDCMPFlags field in your NewWindow structure. You can then handle this
message as normal IDCMP messages. (See chapter 8 IDCMP for more information
about IDCMP messages.)
Once you receive a MENUPICK message you need to check if any items were
selected. The Code field of the IntuiMessage structure will contain a special
code number ("Menu Number") which we can examine in order to see which item was
selected. The menu number is equal to MENUNULL if no item was selected. Use the
function ItemAddress() with a pointer to the menu strip and the menu number as
parameters, and it will return the address of the selected item.
The problem which will arise is that the user can select several items during
one single menu operation, and your program needs to check them all. There is
however an easy solution for this problem. If an item was selected, we can
examine the NextSelect field of that item's structure, and that number is
either MENUNULL (no more items selected), or another special menu number. (If
it was not equal to MENUNULL you should again call the function ItemAddress()
so you get a pointer to the second item's structure, and you should then
examine the NextSelect field of that structure and so on...).
Here is a fragment of a program which handles MENUPICK event:
if( class == MENUPICK )
{
/* The user has released the right mouse button. */
/* The variable menu_number is initialized with the code */
/* value: */
menu_number = code;
/* As long as menu_number is not equal to MENUNULL we */
/* stay in the while loop: */
while( menu_number != MENUNULL )
{
/* Get the address of the item: */
item_address = ItemAddress( &first_menu, menu_number );
/* Process this item... */
/* Get the following item's menu number: */
menu_number = item_address->NextSelect;
}
/* All items which were selected has been processed! */
}
If you have a menu number you can use Intuitions three macros to check which
menu/item/subitem was selected. They all return 0, if it was the first
menu/item/subitem in the list, 1 if it was the second and so on.
MENUNUM( menu_number );
Is equal to 0 if the item was selected from the first menu, 1 if it was from
the second and so on. It is equal to NOMENU if the user did not select any item
from the menus.
ITEMNUM( menu_number );
Is equal to 0 if the firs item was selected in this item list, 1 if it was the
second and so on. It is equal to NOITEM if the user did not select any item.
SUBNUM( menu_number );
Is equal to 0 if it the firs subitem was selected in this subitem list, 1 if it
was the second and so on. It is equal to NOSUB if the user did not select any
subitem.
7.7.2 MENUVERIFY
The MENUVERIFY message tells your program that the user has pressed the right
mouse button, and a menu will be activated. However, the menu strip will first
be activated when you program has replied, and you can therefore, thanks to
this warning, wait with the menu event for a while, or even stop it totally, if
necessary.
If you want your program to receive a message every time the a menu will be
activated you need to set the flag MENUVERIFY in the IDCMPFlags field in your
NewWindow structure. The MENUVERIFY flag acts like the REQVERIFY flag for
requesters.
Here is an example on how your program should handle this verification message,
and how you can cancel a menu operation:
/* Wait until we receive one or more messages: */
Wait( 1 << my_window->UserPort->mp_SigBit );
/* As long as we can collect messages successfully, we will */
/* stay in this while loop: */
while(my_message = GetMsg( my_window->UserPort ));
{
/* After we have collected the message we can read it, */
/* and save any important values which we maybe want to */
/* check later: */
class = my_message->Class;
code = my_message->Code;
/* Before we reply we need to see if we have received a */
/* MENUVERIFY message: */
if( class == MENUVERIFY )
{
/* Yes, we have received a MENUVERIFY message! */
/* The user wants to activate a menu, but the problem */
/* is that we do not know if it is our window's menu */
/* that will be activated, or some other window's menu. */
/* We can however check it by examining the Code field */
/* of the message. If it is equal to MENUWAITING, it */
/* means that it is not your window's menu that will be */
/* activated, but if Code is equal to MENUHOT it means */
/* it is is your window's menu that will be activated! */
if( code == MENUWAITING )
{
/* It is not your window's menu that will be activated! */
/* Your program can take a pause if necessary. You */
/* maybe want to finish of with some drawings, so */
/* your program does not trash any menus. This is */
/* especially important if you are using the low- */
/* level graphics routines since they do not bother */
/* about, menus etc, and will draw over and destroy */
/* anything in their way. */
/* Once the program is ready it should reply the */
/* message, and the menu will be activated. */
}
else
if( code == MENUHOT )
{
/* It is your window's menu that will be activated! */
/* You can now take a pause and finish of with */
/* something before you let Intuition activate the */
/* menu, or you can even stop the whole menu */
/* operation if necessary. If you are writing a */
/* paint program you maybe only want the user to be */
/* able to activate the menu if the pointer is at */
/* the top of the display. That would mean that the */
/* user can draw with the right mouse button, and */
/* when the user wants to make a menu choice, he/ */
/* she simply moves the pointer to the top of the */
/* display, and then presses the right mouse button. */
/* We will now check if the pointer is somewhere at */
/* the top of the display: */
if( my_window->MouseY < 10)
{
/* The Y coordinate of the pointer is at least */
/* less than 10 lines below the TopEdge of the */
/* window. */
/* The menu operation should continue as soon */
/* as possible! */
}
else
{
/* The pointer is below the Title bar of the */
/* window! Cancel the whole menu operation! */
/* To cancel a menu operation you need to change */
/* the Code field to MENUCANCEL. IMPORTANT! Do not */
/* change the code variable since it is just a */
/* copy of the real Code value. What we need to do */
/* is to change the real value, and that is still */
/* OK since we have not replied yet. */
my_message->Code=MENUCANCEL;
}
}
}
/* After we have read the message we reply as fast as */
/* possible: REMEMBER! Do never try to read or change a */
/* message after you have replied! Some other process is */
/* maybe using it. */
ReplyMsg( my_message );
If you set the RMBTRAP flag in your NewWindow's Flags field you tell Intuition
that you do not want to use any menus at all for this window. Your program
could then use the right mouse button for something else. (See chapter 8 IDCMP
for more information about RMBTRAP.)
7.8 MENU NUMBERS
Here is a description of how the "menu numbers" actually work. (This can change
later so do not calculate anything yourself, let Intuition's macros do it
instead.)
The menu number is a 16-bit variable, where the first five bits are used for
the menus, the following six bits are used for the items, and the last five
bits are used for the subitems:
c c c c c b b b b b b a a a a a
| | |
| | > Menu
| > Item
> SubItem
This means the Intuition can "only" handle up to 31 Menus, each with up to 63
Items, where each item can have up to 31 SubItems. I do not think this will be
any restrictions for your program.
If a field is equal to 0 it means the first menu/item/subitem, if it is equal
to 1 it means the second and so on. If all bits are on it means that no
menu/item/subitem was selected. See following example:
The menu number 0xF803 means:
No SubItem, the first item, from the fourth menu.
0xF803 (h) = 1111 1000 0000 0011 (b)
Menu number 11111 000000 00011 (b)
| | |
| | > 00011 = 3 = fourth Menu
| > 000000 = 0 = first Item
> 11111 = 31 = NOSUB
To calculate this you should use Intuition's macros:
MENUNUM( 0xF803 ) == 3 the fourth menu.
ITEMNUM( 0xF803 ) == 0 the first item.
SUBNUM( 0xF803 ) == 31 (NOSUB).
It sometimes happens that you want to go the other way, and calculate your own
menu number. You should then use the macros SHIFTMENU, SHIFTITEM and SHIFTSUB
which does the opposite of MENUNUM etc. If you are going to use the functions
OnMenu() and OffMenu() (explained later), you need to send a menu number as one
of the parameters. If you for example want to "ghost" the second item in the
third menu, you calculate the menu number like this:
menu_number = SHIFTMENU(2) + SHIFTITEM(1) + SHIFTSUB(NOSUB);
[third menu] [second item] [no subitem]
7.9 FUNCTIONS
Here are some commonly used function which affects menus:
SetMenuStrip()
This function connects a menu strip to a window. Remember that the window must
have been opened before you may connect a menu strip to that window.
Synopsis:
SetMenuStrip( my_window, my_menu );
my_window:
(struct Window *) Pointer to the window which the menu strip should be
connected to.
my_menu:
(struct Menu *) Pointer to the first Menu structure in the menu strip.
ClearMenuStrip()
This function removes a menu strip from a window. Remember to always remove the
menu strip before you close the window, or changes the menu strip.
Synopsis:
ClearMenuStrip( my_window );
my_window:
(struct Window *) Pointer to the window which menu strip should be removed.
ItemAddress()
This function returns a pointer to the Menu or Item structure which is
specified by the menu number.
Synopsis:
ItemAddress( my_menu, menu_number );
my_menu:
(struct Menu *) Pointer to the first Menu structure in the menu strip.
menu_number:
(USHORT) This menu number specifies a subitem/item/menu.
OffMenu()
This function can disable a subitem, an item or even a whole menu. The image or
text of the disabled items etc will be "ghosted", and the user can not select
them.
Synopsis:
OffMenu( my_window, menu_number );
my_window:
(struct Window *) Pointer to the window which the menu strip is connected to.
menu_number:
(USHORT) This menu number specifies what should be disabled. Use the macros
SHIFTMENU, SHIFTITEM and SHIFTSUB to calculate the correct menu number. If you
just specify a menu, all items to that menu will be disabled. If you specify a
menu and an item, that item will be disabled, and so all subitems connected to
it if there are any.
OnMenu()
This function can enable a subitem, an item or even a whole menu. The image or
text of the enabled items etc, will become normal (not "ghosted") and the user
can now select them.
Synopsis:
OnMenu( my_window, menu_number );
my_window:
(struct Window *) Pointer to the window which the menu strip is connected to.
menu_number:
(USHORT) This menu number specifies what should be enabled. Use the macros
SHIFTMENU, SHIFTITEM and SHIFTSUB to calculate the correct menu number. If you
just specify a menu, all items to that menu will be enabled. If you specify a
menu and an item, that item will be enabled, so all subitem connected to it if
there are any.
7.10 MACROS
Here are some commonly used macros:
These three macros takes a "menu number" as the only parameter, and examines
it. These are very handy if you have received a menu number, and you want to
check which menu and which item was selected etc:
MENUNUM( menu_number );
Is equal to 0 if the menu number specifies the first menu, 1 if it specifies
the second, and so on. It is equal to NOMENU if it does not specify any menus
at all.
ITEMNUM( menu_number );
Is equal to 0 if the menu number specifies the first item, 1 if it specifies
the second, and so on. It is equal to NOITEM if it does not specify any items
at all.
SUBNUM( menu_number );
Is equal to 0 if the menu number specifies the first subitem, 1 if it specifies
the second, and so on. It is equal to NOSUB if it does not specify any subitems
at all.
These three macros does the opposite of the first three. With help of these
macros you can make your own menu number just by specifying which menu, item
and subitem you want.
SHIFTMENU( menu );
Is equal to a menu number which specifies this menu. ("menu" is a value between
0 and 30, or NOMENU if no menu should be specified.)
SHIFTITEM( item );
Is equal to a menu number which specifies this item. ("item" is a value between
0 and 62, or NOITEM if no item should be specified.)
SHIFTSUB( sub );
Is equal to a menu number which specifies this subitem. ("sub" is a value
between 0 and 30, or NOSUB if no subitem should be specified.)
7.11 EXAMPLES
Example 1
This program opens a normal window to which we connect a menu strip. The menu
consists of four items: Plain, Bold, Underlined and Italic. The user can select
either Plain or a combination of the other styles. (If the user selects Plain
all other modes will be mutual excluded, but if the user on the other hand
selects Bold, Underlined or Italic, only the Plain option will be mutual
excluded.
This example also shows how a program should handle the IDCMP flags, and how to
collect several messages from one single menu event.
Example 2
This example is very similar to Example 1, but we have this time put the edit
styles in a subitem box which is connected to the one and only item box called
"Style".
Example 3
This example is very similar to Example 2, but the user can this time also
access the subitems from the keyboard. For example, to select Bold the user
only needs to press the right Amiga key [A] together with the "B" key.
Example 4
This program opens a normal window to which we connect a menu strip. The menu
consists of two items: Readmode and Editmode. The readmode item is selected and
ghosted, and when the user selects the editmode item, it will become disabled
(ghosted) while the readmode item will be enabled (not ghosted). This means
that if the program is in "readmode", the user should only be able to chose the
"editmode", and v.v. The purpose with this program is to show how you can use
the OnMenu and OffMenu functions in order to make an "user-friendly interface".
Example 5
Exactly as Example 1 except that we have changed Intuition's checkmark to our
own customized "arrow".
Example 6
This program opens a normal window to which we connect a menu strip. The menu
consists of six small dices which are all action items. This example shows how
you can use Images inside a menu.
Example 7
This program opens a normal window to which we connect a menu strip. The menu
consists of one small action item with two images.
Example 8
Same as Example 1 except that we this time will verify any menu operations. If
the user tries to activate this program's menu we check if the position of the
pointer is somewhere at the top of the window (less than 10 lines down). In
that case the menu operation will continue as normal, otherwise we cancel the
menu operation.
IDCMP
8.1 INTRODUCTION
We have in the last four chapters talked about IDCMP, but have never actually
explained what it is. But in this chapter we will at last satisfy your hunger
for more information. IDCMP stands for Intuition's Direct Communications
Messages Ports (nice), and is the most commonly used way of receiving messages
from Intuition, and the only way to communicate to Intuition.
8.2 IDCMP PORTS
When something happens inside the Amiga, a disk is inserted, a gadget is
selected etc, a message is automatically created. Intuition will then examine
the messages and check if your program is interested to hear about it. (Every
window has a list of none or more IDCMP flags which tells Intuition what this
window is interested of.) If a program is interested of the message, that
program will receive a special message (IntuiMessage), which contains
interesting information about the message.
--------------------------- Messages created inside the Amiga.
| DISKINSERTED MENUPICK | For example, a disk is inserted,
| CLOSEWINDOW | a menu is activated, a window is
| NEWSIZE GADGETDOWN | closed etc...
---------------------------
| | | | |
V V V V V
------------- Intuition examines every message
| INTUITION | and checks if any program is
------------- interested of it.
/ \
DISKINSERTED GADGETDOWN If program A is interested of
| | DISKINSERTED messages, Intuition
V V will pass that one along to
------------- ------------- program A. If program B is
| PROGRAM A | | PROGRAM B | interested in GADGETDOWN messages
------------- ------------- program B will receive a message
every time a gadget is selected
in program B's window.
All other messages which no
program were interested in will
be thrown away.
Intuition will always start to examine the active window first, and many IDCMP
messages will probably be "swallowed". If program B is active, and Intuition
has found a GADGETDOWN message, that message would be passed to program B, and
all other programs would never hear about it.
Some messages are important for all programs, such as DISKINSERTED, and will be
passed to ALL "interested" windows. (If a window has its IDCMPFlags field set
to DISKINSERTED, that window is interested about disk inserted messages.)
8.3 HOW TO RECEIVE IDCMP MESSAGES
If you want to receive messages from Intuition you need to:
1. Open an IDCMP port.
2. Wait for messages.
3. Collect the messages.
4. Examine them.
5. Reply. (Tell Intuition that you have read the message)
8.3.1 OPEN IDCMP PORTS
The IDCMP port can be automatically allocated by Intuition when you open a
window. You only need to specify in the NewWindow structure's IDCMPFlags field
which messages you want to receive from Intuition, and the rest is done for
you. For example, if you open a window with the IDCMPFlags field set to
GADGETDOWN, a port would be allocated for you, and your program would receive a
message every time a gadget has been selected.
If you already have opened a window you can later change the IDCMP ports by
calling the function ModifyIDCMP().
8.3.2 WAIT FOR MESSAGES
Once an IDCMP port has been opened your program only need to wait until one or
more messages arrives. There are two different ways of waiting for messages:
1. The Passive Way.
Your program is halted and will only wake up when a message arrives. This will
increase the speed of other applications since the CPU does not need to bother
about your program as long as it is sleeping. Use the function Wait().
2. The Active Way.
Your program tries to collect a message, and if it could not find any message
it tries again. This is necessary if you want your program to continue doing
something, and not stop waiting for a message to arrive.
8.3.3 COLLECT MESSAGES
When you collect a message you should use the function GetMsg(). It will return
a pointer to an IntuiMessage structure, which contains all important
information about the message, or NULL if it could not collect any message.
8.3.4 EXAMINE THE MESSAGE
Once you have collected a message successfully you can examine the IntuiMessage
structure. The IntuiMessag structure look like this:
struct IntuiMessage
{
struct Message ExecMessage;
ULONG Class;
USHORT Code;
USHORT Qualifier;
APTR IAddress;
SHORT MouseX, MouseY;
ULONG Seconds, Micros;
struct Window *IDCMPWindow;
struct IntuiMessage *SpecialLink;
};
ExecMessage:
Used by the Exec so do not touch it.
Class:
Contains the IDCMP flag.
Code:
Contains some special values which is closely related to the IDCMP flag
(Class). For example, if you receive a MENUVERIFY message you can examine the
Code field to see if it is your program's Menu (Code == MENUHOT) or some other
program's Menu (Code == MENUWAITING) that will be displayed. If you on the
other hand receives RAWKEY or VANILLAKEY messages the Code field will contain
the key code and so on.
Qualifier:
If your program receives RAWKEY messages (untranslated keycodes), this field
contains information like if the SHIFT or CTRL key was pressed or not. (A copy
of the ie_Qualifier.)
MouseX:
X position of the pointer relative to the top left corner of your window.
MouseY:
Y position of the pointer relative to the top left corner of your window.
Seconds:
Copy of the system clock's seconds.
Micros:
Copy of the system clock's microseconds.
IAddress:
Pointer to that object that created the message. For example, if you receive a
GADGETDOWN message, this field contains a pointer to the Gadget that was
selected.
IDCMPWindow:
Pointer back to the window that sent this message.
SpecialLink:
Used by Exec and Intuition so do not touch it.
The best way to examine this structure is to copy all important values and then
reply as fast as possible. (Intuition will be slowed down if you do not reply
fast.) You can then (after you have replied) check the copied values.
(Remember! Do not use the IntuiMessage structure any more once you have
replied.)
8.3.5 REPLY
Once your program has read everything it is interested of it should reply back
to Intuition by calling the function ReplyMsg(). This tells Intuition that you
have finished with reading the message.
Important! Once you have replied you may NOT examine/change the IntuiMessage
structure any more. Some other program or Intuition may use it!
8.3.6 EXAMPLE
Here is an example of how your program should collect and process IDCMP
messages: (This is the Passive Way of collecting messages.)
/* 1. Wait until a message arrive: */
Wait( 1 << my_window->UserPort->mp_SigBit );
/* (my_window is a pointer to a window.) */
/* (Do not bother to much about the funny formula.) */
/* 2. Try to collect a message: */
my_message = GetMsg( my_window->UserPort );
/* Could we collect a message? (If message == NULL we have */
/* not collected any message. */
if( my_message )
{
/* YES! We have collected a message successfully. */
/* 3. We should now examine the IntuiMessage structure, */
/* and save any important values. (If we save the */
/* information we can reply as soon as possible, and */
/* later examine the values.) */
class = my_message->Class;
code = my_message->Code;
address = my_message->IAddress;
/* 4. We should now reply since we have finished reading */
/* the IntuiMessage structure. (Your program should */
/* always reply as fast as possible.) */
ReplyMsg( my_message );
/* 5. We can now examine what the message actually was */
/* about: (We have replied so we may NOT examine */
/* the IntuiMessage structure any more, but we may */
/* of course check the variables: class, code and */
/* address.) */
switch( class )
{
case GADGETDOWN: /* A gadget has been pressed. */
case GADGETUP: /* A gadget has been released. */
case MENUPICK: /* A menu item has been selected... */
/* And so on... */
}
}
This example is very fine, but what happens if two messages arrives at the same
time? Well, the first message would be dealt with as normal, but the second
message would never be processed. After we have waited for a message we should
actually be prepared to process many messages. We should therefore use a
while-loop, and stay in the loop as long as we can collect messages
successfully. Once we could not collect any more we should put our task to
sleep again.
Here is a modified, and better, version of the example:
/* 1. Wait until a message arrive: */
Wait( 1 << my_window->UserPort->mp_SigBit );
/* As long as we can collect messages successfully we stay */
/* in the while-loop: */
while( my_message = GetMsg( my_window->UserPort ) )
{
/* The rest is as normal... */
/* 3. We should now examine the IntuiMessage structure, */
/* and save any important values. (If we save the */
/* information we can reply as soon as possible, and */
/* later examine the values.) */
class = my_message->Class;
code = my_message->Code;
address = my_message->IAddress;
/* 4. We should now reply since we have finished reading */
/* the IntuiMessage structure. (Your program should */
/* always reply as fast as possible.) */
ReplyMsg( my_message );
/* 5. We can now examine what the message actually was */
/* about: (We have replied so we may NOT examine */
/* the IntuiMessage structure any more, but we may */
/* of course check the variables: class, code and */
/* address.) */
switch( class )
{
case GADGETDOWN: /* A gadget has been pressed. */
case GADGETUP: /* A gadget has been released. */
case MENUPICK: /* A menu item has been selected... */
/* And so on... */
}
}
8.4 IDCMP FLAGS
We have used several IDCMP flags in the last chapter, such as GADGETDOWN,
MENUPICK, REQVERIFY etc, but here is the total list of all IDCMP flags:
Here are the three IDCMP flags which are closely related to gadgets:
GADGETDOWN:
Your program will this message if a gadget has been selected. (Note, the gadget
must have the GADGIMMEDIATE flag set in its Activation field. If not there will
be no GADGETDOWN message created.)
GADGETUP:
Your program will this message if a gadget has been released. (Note, the gadget
must have the RELVERIFY flag set in its Activation field. If not there will be
no GADGETUP message created.)
CLOSEWINDOW:
Your program will receive this message if the user selects the Close Window
gadget (System Gadget). Remember, the window will not be automatically closed.
It is up to your program if it want to close it or not.
Here are the three IDCMP flags which are closely related to requesters:
REQSET:
Your program will receive this message if a requester has been opened in your
window. This is very handy way to detect if a Double-menu requester has been
activated in your window. (You will receive a message both when a DM-requester
as well as a normal requester has been activated.)
REQCLEAR:
This message tells you that a requester has been cleared from your window.
Note, you will receive this message only when all requesters in your window has
been cleared.
REQVERIFY:
Your program will receive this message if a requester is going to be activated.
However, the requester will first be displayed once you have replied, and this
will therefore allow you to finish of with something before the requester will
be activated. Note, your program will only receive this message when the first
requester is opening in the window. Intuition will then assume that you have
stopped any output to that window.
Here are the two IDCMP flags which are closely related to menus:
MENUPICK:
Your program will receive this message if the user has pressed the right mouse
button. (Note, It does not necessarily mean that an item has been selected.)
The Code field of the message will contain the menu number. If no item was
selected Code will be equal to MENUNULL. Use the Macros described in chapter 7
MENUS, to check which menu/item/subitem was selected.
MENUVERIFY:
Your program will receive this message if a menu is going to be activated. The
menu will, however, first be displayed once you have replied, and this will
therefore allow you to finish of with something before the menu will be opened.
Check if the Code field of the message is equal to MENUHOT which means it is
your menu that will be displayed, or if Code is equal to MENUWAITING, which
means that some other window's menustrip will be displayed. You can even cancel
the whole menu-operation if you want by changing the Code field to MENUCANCEL
before you reply.
Here are the three IDCMP flags which are closely related to the mouse:
MOUSEBUTTONS:
Your program will receive this message if any of the mouse buttons have been
pressed or released. Examine the Code field of the message to see if it is
equal to:
SELECTDOWN: The left mouse button has been pressed.
SELECTUP: The left mouse button has been released.
MENUDOWN: The right mouse button has been pressed.
MENUUP: The right mouse button has been released.
Important! If the user presses the left mouse button while the pointer is
somewhere on a gadget's select box, your program will NOT receive any message.
Remember also that if the user presses the right mouse button a menu strip will
be displayed, and your program will not receive any MENUDOWN message. You need
to set the RMBTRAP flag in the NewWindow structure's Flags field in order to
receive any right mouse buttons event. (No menu can then be used for that
window.)
MOUSEMOVE:
Your program will receive this message if the mouse has been moved. Note, your
window needs to have the REPORTMOUSE flag set in the NewWindow structure's
Flags field, or a gadget in the window needs to have the FOLLOWMOUSE flag set
in the Gadget structure's Activation field.
(Be prepared to receive many messages!)
DELTAMOVE:
Same as MOUSEMOVE except that the movements will be reported as delta movements
instead of absolute positions. Note, your program will continue to receive
delta movements even if the pointer has reached the border of the display.
(Be prepared to receive many messages!)
Here are the five IDCMP flags which are closely related to windows:
NEWSIZE:
Your program will receive this message if the user has resized the window.
Check the windows' Window structure's Width and Height fields to discover the
new size.
SIZEVERIFY:
Your program will receive this message if the user tries to resize the window.
However, Intuition will change the size first when your program has replied,
and this allows you to finish of with something before the window will change
size.
REFRESHWINDOW:
Your program will receive this message if the window needs to be redrawn. This
applies only to SIMPLE_REFRESH and SMART_REFRESH windows. Remember, if you
receive a REFRESHWINDOW event, you need to call the functions BeginRefresh()
and EndReresh() even if you do not redraw anything.
ACTIVEWINDOW:
Your program will receive this message if your window is activated.
INACTIVEWINDOW:
Your program will receive this message if your window is deactivated.
Other IDCMP flags:
RAWKEY:
Your program will receive this message every time the user presses a key. The
Code field of the message will contain the raw keykodes (see Appendix C), and
the Qualifier field of the message contains the qualifier (SHIFT, CTRL etc).
VANILLAKEY:
Your program will receive this message every time the user presses a key. The
Code field of the message will contain the ASCII character (see Appendix D).
DISKINSERTED:
Your program will receive this message if a disk is inserted. All interested
programs will hear about it.
DISKREMOVED:
Your program will receive this message if a disk is removed. All interested
programs will hear about it.
NEWPREFS:
If the the system Preferences is changed (by the user or another program), your
program will receive a NEWPREFS message. Call the function GetPrefs() to get
the new system Preferences. (See chapter 9 MISCELLANEOUS for more information
about Preferences etc.)
INTUITICKS:
Your program will receive this message ten times a second (approximately).
However, if you have not replied on the first INTUITICKS message, the next
message will not be sent.
WBENCHMESSAGE:
If the workbench is opened or closed by a program (calling the functions
OpenWorkBench()/CloseWorkBench() your program will receive a WORKBENCHMESSAGE.
The Code field of the message will be equal to WBENCHOPEN if the WorkBench was
opened, or WBENCHCLOSE if the workbench was closed.
8.5 FUNCTIONS
GetMsg()
This function tries to get a message from a message port.
Synopsis:
my_message = GetMsg( my_message_port );
my_message:
(struct Message *) Pointer to a Message structure, in this case a pointer to an
IntuiMessage structure, or NULL if no message was collected.
my_message_port:
(struct MsgPort *) Pointer to an MsgPort. If you have opened a window, you can
find your window's message port in the Window structure. ( my_window->UserPort
)
ReplyMsg()
This function tells Intuition that you have finished reading the message.
Remember, once you have replied you may not examine or change the IntuiMessage
structure any more.
Synopsis: ReplyMsg( my_message );
my_message:
(struct Message *) Pointer to a Message structure, in this case a pointer to an
IntuiMessage structure.
ModifyIDCMP()
This function changes the Window structure's IDCMPFlags field.
Synopsis:
ModifyIDCMP( my_window, IDCMPFlags );
my_window:
(struct Window *) Pointer to an already opened window.
IDCMPFlags:
(long) None or more IDCMP flags.
If you call this function with no IDCMP flags set, the window's IDCMP Ports
will be closed. On the other hand, if you call this function, with one or more
IDCMP flags set, a Port will be, if necessary, opened for you.
8.6 EXAMPLES
See the examples in chapter 4 (GADGETS) to 7 (MENUS). They will explain how to
use the IDCMP flags: GADGETDOWN, GADGETUP, CLOSEWINDOW, REQSET, REQCLEAR,
REQVERIFY, MENUPICK and MENUVERIFY.
Example 1
This program explains how to use the IDCMP flag MOUSEBUTTONS.
Example 2
This program explains how to use the IDCMP flag MOUSEMOVE.
Example 3
This program explains how to use the IDCMP flags: NEWSIZE, ACTIVEWINDOW and
INACTIVEWINDOW.
Example 4
This program explains how to use the IDCMP flag SIZEVERIFY.
Example 5
This program explains how to use the IDCMP flag RAWKEY.
Example 6
This program explains how to use the IDCMP flag VANILLAKEY.
Example 7
This program explains how to use the IDCMP flags: DISKINSERTED and DISKREMOVED.
Example 8
This program explains how to use the IDCMP flag INTUITICKS.
Example 9
This program explains how to use the IDCMP flag REFRESHWINDOW, and how to
optimize the redrawing of the window.
MISCELLANEOUS
9.1 INTRODUCTION
This is the last chapter about Intuition, and we will therefore finish of by
discussing some special features.
9.2 MEMORY
If you write C programs you will often need to allocate some memory. This
process is normally referred as "dynamic memory allocation" and is used
whenever your program needs some more memory while it is running.
When you allocate memory you need to specify how much you want, and what type
of memory (Fast or Chip). "Exec" will then try to allocated the memory, and
will return a pointer to the memory, or NULL if it could not find a block big
enough.
Once you have allocated the memory, you can use it as much as you want. You
just have to remember that before the program terminates it must have
deallocated all allocated memory. If you forget to deallocate the memory when
you leave, it will be lost, and the only way to get it back is to reboot.
9.2.1 ALLOCATE MEMORY
You usually use the function AllocMem() if you want to allocate memory. You
only need to specify how much memory you need, and what type of memory (Chip,
Fast etc), and AllocMem() will return a pointer to the new memory, or NULL if
no memory could be allocated.
Synopsis
:
memory = AllocMem( size, type );
memory:
(void *) Pointer to the new allocated memory, or NULL if no memory could be
allocated. Remember! Never use memory which you have not successfully
allocated.
size:
(long) The size (in bytes) of the memory you want. (AllocMem() always allocates
memory in multiples of eight bytes. So if you only ask for 9 bytes, Exec would
actually give you 16 Bytes (2*8).)
type:
(long) You need to choose one of the three following types of memory (see
chapter 0 INTRODUCTION for more information about Chip and Fast memory). (The
flags are declared in the header file "exec/memory.h".)
MEMF_CHIP Chip memory. This memory can be accessed by both the main
processor, as well as Chips. Graphics/Sound data MUST therefore be placed in
Chip memory. If it does not matter what type of memory you get (Fast or Chip),
you should try to allocate Fast memory before you allocate Chip memory. (Chip
memory is more valuable than Fast memory.)
MEMF_FAST Fast memory. This memory can only be accessed by the main
processor. (Graphics and Sound data can NOT be stored in Fast memory, use Chip
memory.) This memory is normally a little bit faster than Chip memory, since
only the main processor is working with it, and it is not disturbed by the
Chips.
MEMF_PUBLIC If it does not matter what type of memory you get (you do not
intend to use the memory for Graphics/Sound data), you should use Fast memory.
However, all Amigas do not have Fast memory, since you need to by a memory
expansion in order to get it. If want to tell Exec that you would like to use
Fast memory if there is any, else use Chip memory, you should ask for
MEMF_PUBLIC.
If you want the allocated memory to be cleared (initialized to zeros), you
should set MEMF_CLEAR.
If you need to allocate 150 bytes of Chip memory, you would write:
/* Declare a pointer to the memory you are going to allocate: */
CPTR memory; /* CPTR means memory pointer, declared in the */
/* header file "exec/types.h". "exec/types.h" is */
/* automatically included when you include the */
/* header file "intuition/intuition.h". */
/* Allocate 150 bytes of Chip memory: */
memory = (CPTR) AllocMem( 150, MEMF_CHIP );
/* Have we allocated the memory successfully? */
if( memory == NULL )
/* ERROR! Have not allocated any memory! */
9.2.2 DEALLOCATE MEMORY
All memory that has been allocated MUST be deallocated before your program
terminates. If you forget to deallocate memory which you have allocated, that
memory would be forever lost. The only way of freeing such memory is to reboot.
(Not to be recommended. We are not Demo-writers, are we?)
You free allocated memory by calling the function FreeMem():
Synopsis
:
FreeMem( memory, size );
memory:
(void *) Pointer to some memory which has previously been allocated. Remember!
Never deallocate memory, which you have not allocated, and never use memory
which has been deallocated.
size:
(long) The size (in bytes) of the memory you want to deallocate.
To deallocate the 150 bytes of Chip memory we have previously allocated, we
write:
/* Free 150 bytes of memory: */
FreeMem( memory, 150 );
9.2.3 REMEMBER MEMORY
If you allocate memory several times, and in different quantities, it can be
very hard to remember to deallocate all memory correctly. However, do not
despair. Intuition have a solution for you. You can use the function
AllocRemember() which calls the function AllocMem(), but will also allocate
memory for a Remember structure which is automatically initialized for you.
Every time you allocate memory with the AllocRemember() function, the Remember
structures are linked together, and the information about the memory (size and
position) is remembered. Once you want to deallocate the memory, you only need
to call the function FreeRemember(), and all memory is deallocated for you
automatically.
The Remember structure look like this:
struct Remember
{
struct Remember *NextRemember;
ULONG RememberSize;
UBYTE *Memory;
};
The AllocRemember() function is called like this: (Very similar to the
AllocMem() function.)
Synopsis
:
memory = AllocRemember( remember, size, type );
memory:
(char *) Pointer to the new allocated memory, or NULL if no memory could be
allocated. Remember! Never use memory which you have not successfully
allocated.
remember:
(struct Remember **) Address of a pointer to a Remember structure. Before you
call the AllocRemember() function for the first time you should set this
pointer to NULL. (Note that it is a pointer to a pointer!)
size:
(long) The size (in bytes) of the memory you want. (AllocMem() always allocates
memory in multiples of eight bytes. So if you only ask for 29 bytes, Exec would
actually give you 32 Bytes (4*8).)
type:
(long) You need to choose one of the three following types of memory (see
chapter 0 INTRODUCTION for more information about Chip and Fast memory):
MEMF_CHIP Chip memory. This memory can be accessed by both the main
processor, as well as the Chips. Graphics/Sound data MUST therefore be placed
in Chip memory. If it does not matter what type of memory you get (Fast or
Chip), you should try to allocate Fast memory before you allocate Chip memory.
(Chip memory is more valuable than Fast memory.)
MEMF_FAST Fast memory. This memory can only be accessed by the main
processor. (Graphics and Sound data can NOT be stored in Fast memory, use Chip
memory.) This memory is normally a little bit faster than Chip memory, since
only the main processor is working with it, and it is not disturbed by the
Chips.
MEMF_PUBLIC If it does not matter what type of memory you get (you do not
intend to use the memory for Graphics/Sound data), you should use Fast memory.
However, all Amigas do not have Fast memory, since you need to by a memory
expansion in order to get it. If want to tell Exec that you would like to use
Fast memory if there is any, else use Chip memory, you should ask for
MEMF_PUBLIC.
If you want the allocated memory to be cleared (initialized to zeros), you
should set MEMF_CLEAR.
When you want to deallocate the memory you only need to call the function
FreeRemember() function. You can if you want, deallocate only the Remember
structures, and take care of the deallocation yourself, but be careful. The
FreeRemember() function is called like this:
Synopsis
:
FreeRemember( remember, everything );
remember:
(struct Remember **) Address of a pointer to the first Remember structure
(initialized by the AllocRemember() function). (Note that it is a pointer to a
pointer!)
everything:
(long) A boolean value. If everything is equal to TRUE, all memory (both the
allocated memory and the Remember structures) are deallocated. However, if
everything is equal to FALSE, only the Remember structures are deallocated, and
you have to deallocate the memory yourself.
Here is a short example which shows how to use the AllocRemember(), and the
FreeRemember() functions:
struct Remember *remember = NULL;
CPTR memory1, memory2, memory3;
/* Allocate 350 bytes of Chip memory, which is cleared: */
memory1 = AllocRemember( &remember, 350, MEMF_CHIP|MEMF_CLEAR );
if( memory1 == NULL )
Clean up and leave;
/* Allocate 900 bytes of memory (any type, Fast if possible): */
memory2 = AllocRemember( &remember, 900, MEMF_PUBLIC );
if( memory2 == NULL )
Clean up and leave;
/* Allocate 100 bytes of Chip memory: *
memory3 = AllocRemember( &remember, 100, MEMF_CHIP );
if( memory3 == NULL )
Clean up and leave;
...
/* Deallocate all memory with one single call: */
FreeRemember( &remember, TRUE );
If we wanted, we could have deallocated all Remember
structures, and then deallocate the memory ourself with help
of the normal FreeMem() function:
/* Deallocate only the Remember structures: */
FreeRemember( &remember, FALSE );
FreeMem( memory1, 350 );
FreeMem( memory2, 900 );
FreeMem( memory3, 100 );
9.3 PREFERENCES
When the system starts up, Intuition is initialized to some default values.
However, if there exist a file called: "system-configuration" in the "devs"
directory on the system disk, that file is used to set the system values,
instead of the default values.
The user can with the "Preferences" program change the system values, and/or
the "system-configuration" file. If the user selects the "USE" command, only
the system values are changed, while if the user selects the "SAVE" command,
both the system values, as well as the "system-configuration" file are updated.
Your program can get a copy of the system values by calling the function
GetPrefs(). If you want to get a copy of the default values you use the
function GetDefPrefs(). When you get a copy of the Preferences data, you can
decide how much data you want copied. You can therefore, if you want, only copy
parts of the structure, and do not need to allocate memory for the whole
structure. The most important values are because of that placed in the
beginning of the structure. The Preferences structure look like this: (See file
"intuition/preferences.h" for more information. It is on the fourth Lattice C
disk, in the "Compiler_Headers" directory.)
struct Preferences
{
BYTE FontHeight;
UBYTE PrinterPort;
USHORT BaudRate;
struct timeval KeyRptSpeed;
struct timeval KeyRptDelay;
struct timeval DoubleClick;
USHORT PointerMatrix[POINTERSIZE];
BYTE XOffset;
BYTE YOffset;
USHORT color17;
USHORT color18;
USHORT color19;
USHORT PointerTicks;
USHORT color0;
USHORT color1;
USHORT color2;
USHORT color3;
BYTE ViewXOffset;
BYTE ViewYOffset;
WORD ViewInitX, ViewInitY;
BOOL EnableCLI;
USHORT PrinterType;
UBYTE PrinterFilename[FILENAME_SIZE];
USHORT PrintPitch;
USHORT PrintQuality;
USHORT PrintSpacing;
UWORD PrintLeftMargin;
UWORD PrintRightMargin;
USHORT PrintImage;
USHORT PrintAspect;
USHORT PrintShade;
WORD PrintThreshold;
USHORT PaperSize;
UWORD PaperLength;
USHORT PaperType;
UBYTE SerRWBits;
UBYTE SerStopBuf;
UBYTE SerParShk;
UBYTE LaceWB;
UBYTE WorkName[FILENAME_SIZE];
BYTE RowSizeChange;
BYTE ColumnSizeChange;
UWORD PrintFlags;
UWORD PrintMaxWidth;
UWORD PrintMaxHeight;
UBYTE PrintDensity;
UBYTE PrintXOffset;
UWORD wb_Width;
UWORD wb_Height;
UBYTE wb_Depth;
UBYTE ext_size;
};
You call the function GetPrefs() like this:
Synopsis:
pref = GetPrefs( buffer, size );
pref:
(struct Preferences *) Pointer to your preferences. Same as your memory pointer
(buffer), but is returned so you can check if you got a copy or not. If you
could not get a copy of the preferences, the function returns NULL.
buffer:
(struct Preferences *) Pointer to the memory buffer which should be used to
store a copy of the preferences in.
size:
(long) The number of bytes you want to copy to the buffer. Important, the
buffer must be at least as big as the number of bytes you want to copy.
You call the function GetDefPrefs() like this:
Synopsis:
pref = GetPrefs( buffer, size );
pref:
(struct Preferences *) Pointer to the default preferences. If the function
could not make a copy of the preferences, the function returns NULL.
buffer:
(struct Preferences *) Pointer to the memory buffer which should be used to
store a copy of the default preferences in.
size:
(long) The number of bytes you want to copy to the buffer. Important, the
buffer must be at least as big as the number of bytes you want to copy.
Here is an example on how to get a copy of the current preferences:
/* Declare a preferences structure: */
struct Preferences pref;
/* Try to get a copy of the current preferences: */
if( GetPrefs( &pref, sizeof(pref) ) == NULL )
/* Could not get a copy of the preferences! */
Once you have got a copy of the current/default preferences we can start to
check the settings.
You can, if you want, change some values, and then save them as new
preferences. IMPORTANT! You should never mess with the settings since it is the
user's own preferences, and should therefore NOT be changed unless the user
really WANT to alter them.
You set new preferences by calling the function SetPrefs():
Synopsis:
SetPrefs( pref, size, doit );
pref:
(struct Preferences *) Pointer to your modified Preferences structure.
size:
(long) The number of bytes you want to change.
doit:
(long) Boolean value which if FALSE, changes the preferences, but will not send
a NEWPREFS message. If doit is equal to TRUE, the settings will be changed, and
a NEWPREFS message will be sent. As long as the user is changing the values,
doit should be FALSE, but when the user has finished, set it to TRUE, and all
programs will get a NEWPREFS message.
9.4 WARNINGS
There exist three levels of warnings you can give the user when something goes
wrong:
1. If you just want to get the users attention about something, but nothing
really dangerous has happened, you should call the function DisplayBeep(). It
will flash the colours of the screen.
Synopsis:
DisplayBeep( screen );
screen:
(struct Screen *) Pointer to the screen, which colours you want to flash. If
you have not opened a screen yourself (you are using the Workbench Screen), you
can find a pointer to that screen in the Window structure: (my_window is a
pointer to an opened window) DisplayBeep( my_window->WScreen );
2. If something important has happened, or if you want the user to take some
action (select something) etc, open a Requester. (See chapter 5 REQUESTERS for
more information.)
3. If something TERRIBLE is happening, the system is breaking down, open an
Alert. (See chapter 6 ALERTS for more information.)
9.5 DOUBLE CLICK
There are five different mouse actions:
1. Press a button
The user can press on a button.
2. Release a button
The user can release a previously pressed button.
3. Click a button
Quickly pressing and releasing a button.
4. Double-click a button
Quickly pressing/releasing a button twice.
5. Drag
Hold a button pressed, while moving the mouse.
Use the IDCMP flags SELECTDOWN, SELECTUP, MENUDOWN, and MENUUP in order to
receive mouse-buttons events. (See chapter 8 IDCMP for more information.)
If you want to check if the user double-clicked one of the mouse buttons, you
can use the function DoubleClick(). You give the function the current as well
as the previous time when the button was pressed, and it will check the
preferences and return TRUE if the two button events happened within the time
limit. (The user can change the time limit for double-clicking events.)
Synopsis
:
double = DoubleClick( sec1, mic1, sec2, mic2 );
double:
(long) If the two button events happened within the current time limit, the
function will return TRUE, else it will return FALSE.
sec1:
(long) Time (seconds) when the button was pressed for the first time.
mic1:
(long) Time (micros) when the button was pressed for the first time.
sec2:
(long) Current time (seconds).
mic2:
(long) Current Time (micros).
Here is a short example on how to check double-click events:
struct IntuiMessage *message;
ULONG sec1, mic1, sec2, mic2;
... ... ...
if( message->Class == MOUSEBUTTONS )
{
/* A mouse button was pressed/released. */
if( message->Code == SELECTDOWN )
{
/* The left mouse button was pressed. */
/* Save the old time: */
sec2 = sec1;
mic2 = mic1;
/* Get the new time: */
sec1 = message->Seconds;
mic1 = message->Micros;
/* Check if it was a double-click or not: */
if( DoubleClick( sec2, mic2, sec1, mic1 ) )
{
printf("Double-Click!\n");
/* Reset the values: */
sec1 = 0;
mic1 = 0;
}
}
}
9.6 TIME
You can get the current time by calling the function CurrentTime():
Synopsis
:
CurrentTime( seconds, micros );
seconds:
(long *) Pointer to an ULONG variable which will be initialized with the
current seconds stamp.
micros:
(long *) Pointer to an ULONG variable which will be initialized with the
current micros stamp.
Here is a short example:
ULONG seconds, micros;
CurrentTime( &seconds, µs );
9.7 STYLE
Since Intuition is the interface between computer and the user, it is important
that there are some standards concerning gadgets, requesters, menus, mouse,
etc. If similar programs use the same type of style, the user will much faster
learn to handle them. You, as the programmer, have therefore to make sure that
your program is easily understandable and foolproof. Make your program easy to
learn, and fun to handle!
9.7.1 GADGETS
Remember to make the gadgets easily recognizable, and understandable. Put short
words like "CANCEL", "OK" in the gadget, or use graphics symbols. Remember to
disable (ghosted) a gadget when it becomes nonfunctional.
9.7.2 REQUESTERS
Requesters have two main functions: They can inform the user about something,
and/or ask the user to take some action. It is therefore important that it is
easy for the user to understand what has or will happen, and what he/she has to
do. Use colourful graphics if necessary, and remember that if you want some
action from the user, always give him/her a way out without affecting anything
(CANCEL).
A requester which is meaningless should be taken away. Use the functions
EndRequest(), ClearDMRequest().
Place the OK/YES/TRUE gadget (if there exist one) in the bottom left corner,
and the CANCEL/NO/FALSE gadget in the bottom right corner. There should always
be an escape (CANCEL) gadget in every requester!
---------------------------
| OK to delete file? |
| |
| ---------- ---------- |
| | DELETE | | CANCEL | |
| ---------- ---------- |
---------------------------
9.7.3 MENUS
Menu items/subitems which are nonfunctional should be disabled (ghosted). Use
the function OffMenu().
There are two menus, project and edit menu, which many program will use, and
should therefore look something like this:
PROJECT
Item Function
---------------------------------------------------------------
New Creates a new project.
Open Opens an old project.
Save Saves current project.
Save as Saves current project under a new name.
Print Prints the whole project.
Print as Prints parts of a project, and/or with new settings.
Quit Quits. Remember to ask the user if he/she really
wants to quit, and if he/she wants to save the
project.
EDIT
Item Function
---------------------------------------------------------------
Undo Undoes the last operation.
Cut Cuts a part away, and stores it in the Clipboard.
Copy Copies a part of the project into the Clipboard.
Paste Puts a copy of the Clipboard into the project.
Erase Deletes a part of the project without putting it into
the Clipboard.
Remember to enable shortcuts for often used menu-functions. Here are some
standard command key styles:
Amiga + key Function
---------------------------------------------------------------
N New
O Open
S Save
Q Quit
U Undo
X Cut
C Copy
P Past
9.7.4 MOUSE
The left mouse button is used for "selection", while the right mouse button is
used for "information transfer". The left mouse button is therefore used for
selecting gadgets etc, while menu functions and double-menu requesters etc, use
the right mouse button.
9.8 FUNCTIONS
AllocMem()
This function allocates memory. You specifies what type and how much you want,
and it returns a pointer to the allocated memory, or NULL if there did not
exist enough memory.
Synopsis:
memory = AllocMem( size, type );
memory:
(void *) Pointer to the new allocated memory, or NULL if no memory could be
allocated. Remember! Never use memory which you have not successfully
allocated.
size:
(long) The size (in bytes) of the memory you want. (AllocMem() always allocates
memory in multiples of eight bytes. So if you only ask for 9 bytes, Exec would
actually give you 16 Bytes (2*8).)
type:
(long) You need to choose one of the three following types of memory (see
chapter 0 INTRODUCTION for more information about Chip and Fast memory):
MEMF_CHIP Chip memory. This memory can be accessed by both the main
processor, as well as the Chips. Graphics/Sound data MUST therefore be placed
in Chip memory. If it does not matter what type of memory you get (Fast or
Chip), you should try to allocate Fast memory before you allocate Chip memory.
(Chip memory is more valuable than Fast memory.)
MEMF_FAST Fast memory. This memory can only be accessed by the main
processor. (Graphics and Sound data can NOT be stored in Fast memory, use Chip
memory.) This memory is normally a little bit faster than Chip memory, since
only the main processor is working with it, and it is not disturbed by the
Chips.
MEMF_PUBLIC If it does not matter what type of memory you get (you do not
intend to use the memory for Graphics/Sound data), you should use Fast memory.
However, all Amigas do not have Fast memory, since you need to by a memory
expansion in order to get it. If want to tell Exec that you would like to use
Fast memory if there is any, else use Chip memory, you should ask for
MEMF_PUBLIC.
If you want the allocated memory to be cleared (initialized to zeros), you
should set the flag MEMF_CLEAR.
FreeMem()
This function deallocated previously allocated memory. Remember to deallocate
all memory you have taken, and never deallocate memory which you have not
taken.
Synopsis:
FreeMem( memory, size );
memory:
(void *) Pointer to some memory which has previously been allocated. Remember!
never use memory which has been deallocated.
size:
(long) The size (in bytes) of the memory you want to deallocate.
AllocRemember()
This function allocates both memory (same as AllocMem), but will also allocate
space for a Remember structure which are initialized with the size of the
allocated memory, and a pointer to that memory. Each time the program allocates
memory with this function, the Remember structures are linked together.
Since the Remember structures contains all necessary information about the
memory, and are linked together, all memory can be deallocated with one single
function call (FreeRemember()).
Synopsis:
memory = AllocRemember( remember, size, type );
memory:
(char *) Pointer to the new allocated memory, or NULL if no memory could be
allocated. Remember! Never use memory which you have not successfully
allocated.
remember:
(struct Remember **) Address of a pointer to a Remember structure. Before you
call the AllocRemember() function for the first time you should set this
pointer to NULL. (Note that it is a pointer to a pointer!)
size:
(long) The size (in bytes) of the memory you want. (AllocMem() always allocates
memory in multiples of eight bytes. So if you only ask for 9 bytes, Exec would
actually give you 16 Bytes (2*8).)
type:
(long) You need to choose one of the three following types of memory (see
chapter 0 INTRODUCTION for more information about Chip and Fast memory):
MEMF_CHIP Chip memory. This memory can be accessed by both the main
processor, as well as the Chips. Graphics/Sound data MUST therefore be placed
in Chip memory. If it does not matter what type of memory you get (Fast or
Chip), you should try to allocate Fast memory before you allocate Chip memory.
(Chip memory is more valuable than Fast memory.)
MEMF_FAST Fast memory. This memory can only be accessed by the main
processor. (Graphics and Sound data can NOT be stored in Fast memory, use Chip
memory.) This memory is normally a little bit faster than Chip memory, since
only the main processor is working with it, and it is not disturbed by the
Chips.
MEMF_PUBLIC If it does not matter what type of memory you get (you do not
intend to use the memory for Graphics/Sound data), you should use Fast memory.
However, all Amigas do not have Fast memory, since you need to by a memory
expansion in order to get it. If want to tell Exec that you would like to use
Fast memory if there is any, else use Chip memory, you should ask for
MEMF_PUBLIC.
If you want the allocated memory to be cleared (initialized to zeros), you
should set the flag MEMF_CLEAR.
FreeRemember()
This function deallocates all memory which has been allocated by the
AllocRemember() function. Note, you can deallocate all Remember structures
only, and deallocate the memory yourself, if you want to.
Synopsis:
FreeRemember( remember, everything );
remember:
(struct Remember **) Address of a pointer to the first Remember structure
(initialized by the AllocRemember() function). (Note that it is a pointer to a
pointer!)
everything:
(long) A boolean value. If everything is equal to TRUE, all memory (both the
allocated memory and the Remember structures) are deallocated. However, if
everything is equal to FALSE, only the Remember structures are deallocated, and
you have to deallocate the memory yourself.
GetPrefs()
This function makes a copy of the Preferences structure.
Synopsis:
pref = GetPrefs( buffer, size );
pref:
(struct Preferences *) Pointer to your preferences. Same as your memory pointer
(buffer), but is returned so you can check if you got a copy or not. If you
could not get a copy of the preferences, the function returns NULL.
buffer:
(struct Preferences *) Pointer to the memory buffer which should be used to
store a copy of the preferences in.
size:
(long) The number of bytes you want to copy to the buffer. Important, the
buffer must be at least as big as the number of bytes you want to copy.
GetDefPrefs()
This function makes a copy of the default Preferences structure.
Synopsis:
pref = GetPrefs( buffer, size );
pref:
(struct Preferences *) Pointer to the default preferences. If the function
could not make a copy of the preferences, the function returns NULL.
buffer:
(struct Preferences *) Pointer to the memory buffer which should be used to
store a copy of the default preferences in.
size:
(long) The number of bytes you want to copy to the buffer. Important, the
buffer must be at least as big as the number of bytes you want to copy.
SetPrefs()
This function saves a modified preferences structure. Do NOT change the
preferences unless the user really WANTS to!
Synopsis:
SetPrefs( pref, size, doit );
pref:
(struct Preferences *) Pointer to your modified Preferences structure.
size:
(long) The number of bytes you want to change.
doit:
(long) Boolean value which if FALSE, changes the preferences, but will not send
a NEWPREFS message. If doit is equal to TRUE, the settings will be changed, and
a NEWPREFS message will be sent. As long as the user is changing the values,
doit should be FALSE, but when the user has finished, set it to TRUE, and all
programs will get a NEWPREFS message.
DisplayBeep()
This function flashes the screen's colours. Can be used whenever you want to
catch the user's attention.
Synopsis:
DisplayBeep( screen );
screen:
(struct Screen *) Pointer to the screen, which colours you want to flash. If
you have not opened a screen yourself (you are using the Workbench Screen), you
can find a pointer to that screen in the Window structure: (my_window is a
pointer to an opened window) DisplayBeep( my_window->WScreen );
DoubleClick()
This function checks if the user double-clicked on one of the mouse buttons.
You give the function the current as well as the previous time when the button
was pressed, and it will check the preferences and return TRUE if the two
button events happened within the time limit.
Synopsis:
double = DoubleClick( sec1, mic1, sec2, mic2 );
double:
(long) If the two button events happened within the current time limit, the
function will return TRUE, else it will return FALSE.
sec1:
(long) Time (seconds) when the button was pressed for the first time.
mic1:
(long) Time (micros) when the button was pressed for the first time.
sec2:
(long) Current time (seconds).
mic2:
(long) Current Time (micros).
CurrentTime()
This function gives the current time.
Synopsis:
CurrentTime( seconds, micros );
seconds:
(long *) Pointer to an ULONG variable which will be initialized with the
current seconds stamp.
micros:
(long *) Pointer to an ULONG variable which will be initialized with the
current micros stamp.
9.9 EXAMPLES
Example 1
This example shows how to allocate, and deallocate memory.
Example 2
This example shows how to allocate and deallocate memory with help of the
functions AllocRemember(), and FreeRemember().
Example 3
This example shows how to get a copy of the preferences.
Example 4
This example shows how to handle double mouse button events.
Example 5
This example prints out the current time.